东张西望

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)
}

总结

参考

#golang