Go 中的接口可能给底层类型带来歧义。事实上,空接口可以接收任何具体值(包括基本类型)。类型断言让我们能用这样的语法提取接口值底层的具体值:interfaceVariable.(concreteType)。
如果我们把这个语句的结果赋给单个值,就等于断言该接口变量持有的是指定具体类型的值。因此,如果接口值并不是指定的具体类型,运行时可能会 panic。例如:
var input interface{} = 12
str := input.(string) // panic at runtime since input is not a string!
我们可以利用类型断言的两个返回值,来判断接口值是否持有某个具体类型:一个是底层值,另一个是表示断言是否成功的布尔值。例如:
str, ok := input.(string) // no panic if input is not a string
如果 input 持有的是 string,那么 str 就是底层值,ok 为 true。如果 input 不是 string,那么 str 会是 string 类型的零值(即 "",空字符串),ok 为 false。这两种情况都不会发生 panic。
这种写法很常见:
str, ok := input.(string)
if !ok {
str = "a default value"
}
类型 switch 可以连续执行多个类型断言。它的语法和类型断言一样(interfaceVariable.(concreteType)),只是不用具体的 concreteType,而是使用关键字 type。下面是一个例子:
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)
}