En Go, les interfaces peuvent introduire une ambiguïté sur le type sous-jacent.
En fait, l'interface vide peut contenir absolument n'importe quelle valeur concrète (y compris les types primitifs).
Une assertion de type permet d'extraire la valeur concrète sous-jacente d'une valeur d'interface, avec cette syntaxe : interfaceVariable.(concreteType).
Si on affecte le résultat de cette instruction à une seule valeur, on affirme que la variable d'interface contient une valeur du type concret. Par conséquent, un panic peut survenir à l'exécution si la valeur d'interface n'a pas le type concret indiqué. Par exemple :
var input interface{} = 12
str := input.(string) // panic at runtime since input is not a string!
On peut vérifier si une valeur d'interface contient un type concret donné en utilisant les deux valeurs de retour de l'assertion de type : la valeur sous-jacente et un booléen qui indique si l'assertion a réussi. Par exemple :
str, ok := input.(string) // no panic if input is not a string
Si input contient une string, alors str sera la valeur sous-jacente et ok vaudra vrai.
Si input ne contient pas de string, alors str aura la valeur zéro du type string (c'est-à-dire "", la string vide) et ok vaudra faux.
Aucun panic ne se produit, dans un cas comme dans l'autre.
On rencontre souvent ce genre d'idiome :
str, ok := input.(string)
if !ok {
str = "a default value"
}
Un switch de type permet d'enchaîner plusieurs assertions de type.
Il a la même syntaxe qu'une assertion de type (interfaceVariable.(concreteType)), mais au lieu d'un concreteType précis, il utilise le mot-clé type.
Voici un exemple :
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)
}