Interfaces in Go can introduce ambiguity about the underlying type.
In fact, the empty interface can take any concrete value at all (including primitives).
A type assertion allows us to extract the interface value's underlying concrete value using this syntax: interfaceVariable.(concreteType).
If we assign the result of this statement to a single value, we assert that the interface variable holds a value of the concrete type. As a result, it may panic at runtime if the interface value does not have the specified concrete type. For example:
var input interface{} = 12
str := input.(string) // panic at runtime since input is not a string!
We can test whether an interface value holds a specific concrete type by making use of both return values of the type assertion: the underlying value and a boolean value that reports whether the assertion succeeded. For example:
str, ok := input.(string) // no panic if input is not a string
If input holds a string, then str will be the underlying value and ok will be true.
If input does not hold a string, then str will be the zero value of type string (ie. "" - the empty string) and ok will be false.
No panic occurs in any case.
It is common to see this sort of idiom:
str, ok := input.(string)
if !ok {
str = "a default value"
}
A type switch can perform several type assertions in a row.
It has the same syntax as a type assertion (interfaceVariable.(concreteType)), but instead of a specific concreteType it uses the keyword type.
Here is an example:
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)
}