golang 的类型转换和类型断言
在浏览 [[Go by Example]] 时,遇到了类型断言这个概念,这里参考 [[《Effective Go》]] 解释一下类型断言。
下面这段代码定义了一种错误类型 argError,该类型实现了 Error 方法,所以它是实现了 error 接口的具体类型。这里 err.(*argError)
是什么意思?这需要从接口转换开始讲起。
_, err := f2(42)
if ae, ok := err.(*argError); ok {
fmt.Println(ae.arg)
fmt.Println(ae.prob)
}
接口转换
类型转换可以根据一个值的类型进入不同的条件分支。golang 中可以用 switch 语句进行接口转换,例如
type Stringer interface {
String() string
}
var value interface{} // Value provided by caller.
switch str := value.(type) {
case string:
return str
case Stringer:
return str.String()
}
这段代码的功能是将一个[[interface{} 类型]]转换成字符串或者一个返回字符串的接口方法。 这个功能比较适合使用混合类型的场景。
对于更简单的情况,我们明确地知道一个接口类型的值的具体类型是什么,然后我们想得到这个具体类型,从而能访问到这个具体类型特有的成员,这时候就可以类型断言来完成。
类型断言
类型断言与类型转换语句类似,但是用的不是 type
关键词,而是一个具体的类型 value.(typeName)
,例如
str := value.(string)
上面这句在 value 不是字符串时会抛出 panic,可以采用另一种方式避免抛出 panic
str, ok := value.(string)
if ok {
fmt.Printf("string value is: %q\n", str)
} else {
fmt.Printf("value is not a string\n")
}
如果断言失败,ok 的值就是 false。
继续上面的那个场景来说,当接口类型 err 是 argError 指针类型时,这个变量会被赋值给变量 ae。
_, err := f2(42)
if ae, ok := err.(*argError); ok {
fmt.Println(ae.arg)
fmt.Println(ae.prob)
}
总结
- 类型转换是形如
switch value.(type) {case int: xxx case string: xxx}
的语句。 - 类型断言是形如
value.(typeName)
的语句。其中 value 是一个接口类型,typeName 是实现了这个接口的一个具体类型。 - 类型断言的功能是将==接口类型转换成具体类型。
- 类型断言是简化版的类型转换。
参考
- [[《Effective Go》]]的interface conversions
- 上文的中文翻译 仅供参考,感觉翻译得不太行