As interfaces em Go podem introduzir ambiguidade em relação ao tipo subjacente.
De facto, a interface vazia pode assumir qualquer valor concreto (incluindo tipos primitivos).
Uma asserção de tipo permite-nos extrair o valor concreto subjacente de um valor de interface com esta sintaxe: interfaceVariable.(concreteType).
Se atribuirmos o resultado desta instrução a um único valor, afirmamos que a variável de interface contém um valor do tipo concreto. Por conseguinte, pode entrar em pânico em tempo de execução se o valor de 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 devolvidos pela asserção de tipo: o valor subjacente e um valor do tipo Boolean que indica se a asserção foi bem-sucedida. Por exemplo:
str, ok := input.(string) // no panic if input is not a string
Se input contiver uma string, então str será o valor subjacente e ok será true.
Se input não contiver uma string, então str será o valor zero do tipo string (ou seja, "", a string vazia) e ok será false.
Em nenhum dos casos ocorre um pânico.
É comum ver este tipo de idiomatismo:
str, ok := input.(string)
if !ok {
str = "a default value"
}
Um switch de tipo pode realizar várias asserções de tipo seguidas.
Tem a mesma sintaxe que uma asserção de tipo (interfaceVariable.(concreteType)), mas, em vez de um concreteType específico, usa a palavra-chave type.
Eis 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)
}