As interfaces em Go podem introduzir ambiguidade sobre o tipo subjacente.
Na verdade, a interface vazia pode assumir qualquer valor concreto (incluindo tipos primitivos).
Uma asserção de tipo permite extrair o valor concreto subjacente de um valor de interface usando esta sintaxe: interfaceVariable.(concreteType).
Se atribuirmos o resultado dessa instrução a um único valor, estamos afirmando que a variável de interface contém um valor do tipo concreto. Por isso, a operação pode causar um panic em tempo de execução se o valor da interface não tiver o tipo concreto especificado. Por exemplo:
var input interface{} = 12
str := input.(string) // panic at runtime since input is not a string!
Podemos testar se um valor de interface contém um tipo concreto específico usando os dois valores de retorno da asserção de tipo: o valor subjacente e um valor Boolean que informa se a asserção teve sucesso. Por exemplo:
str, ok := input.(string) // no panic if input is not a string
Se input contém uma string, str será o valor subjacente e ok será true.
Se input não contém uma string, str será o valor zero do tipo string (ou seja, "", a string vazia) e ok será false.
Em nenhum dos casos ocorre um panic.
É comum ver esse tipo de construção:
str, ok := input.(string)
if !ok {
str = "a default value"
}
Um switch de tipo pode fazer várias asserções de tipo em sequência.
Ele tem a mesma sintaxe de uma asserção de tipo (interfaceVariable.(concreteType)), mas em vez de um concreteType específico, usa a palavra-chave type.
Veja um exemplo:
var i interface{} = 12 // try: 12.3, true, int64(12), []int{}, map[string]int{}
switch v := i.(type) {
case int:
fmt.Printf("the integer %d\n", v)
case string:
fmt.Printf("the string %s\n", v)
default:
fmt.Printf("type, %T, not handled explicitly: %#v\n", v, v)
}