Las interfaces en Go pueden introducir ambigüedad sobre el tipo subyacente.
De hecho, la interfaz vacía puede contener cualquier valor concreto (incluidos los primitivos).
Una aserción de tipo nos permite extraer el valor concreto subyacente del valor de la interfaz con esta sintaxis: interfaceVariable.(concreteType).
Si asignamos el resultado de esta instrucción a un único valor, afirmamos que la variable de interfaz contiene un valor del tipo concreto. Como consecuencia, puede provocar un pánico en tiempo de ejecución si el valor de la interfaz no tiene el tipo concreto especificado. Por ejemplo:
var input interface{} = 12
str := input.(string) // panic at runtime since input is not a string!
Podemos comprobar si un valor de interfaz contiene un tipo concreto específico haciendo uso de los dos valores devueltos de la aserción de tipo: el valor subyacente y un valor Boolean que indica si la aserción ha tenido éxito. Por ejemplo:
str, ok := input.(string) // no panic if input is not a string
Si input contiene un string, entonces str será el valor subyacente y ok será true.
Si input no contiene un string, entonces str será el valor cero del tipo string (es decir, "", el string vacío) y ok será false.
En ningún caso se produce un pánico.
Es habitual encontrarse con este tipo de expresión:
str, ok := input.(string)
if !ok {
str = "a default value"
}
Un switch de tipos puede realizar varias aserciones de tipo seguidas.
Tiene la misma sintaxis que una aserción de tipo (interfaceVariable.(concreteType)), pero en lugar de un concreteType específico usa la palabra clave type.
Aquí tienes un ejemplo:
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)
}