07.3 类型断言

类型断言的表示方法是x.(T),其中x是接口类型的变量,T是要判断的类型。也就是说,存储在x接口类型的变量中的实际值是T类型,并且T必须满足x的接口类型变量!以下的段落和代码示例,将澄清类型断言的这个相对不容易理解的概念。

类型断言做两件事:第一件事是检查接口类型变量是否是特定的类型,这样使用时,类型断言返回两个值:基础值和bool值。虽然基础值是您可能想要使用的值,但是布尔值告诉您类型断言是否成功!

类型断言所做的第二件事是允许您使用存储在接口中的具体值或将其分配给新变量。这意味着如果接口中有一个int变量,可以使用类型断言获取该值。

但是,如果类型断言不成功,并且没有处理该失败,那么您的程序将触发panic异常。接下来我们分两部分介绍assertion.go程序。第一部分包含以下Go代码:

package main
import (
"fmt"
)
func main() {
var myInt interface{} = 123
k, ok := myInt.(int)
if ok {
fmt.Println("Success:", k)
}
v, ok := myInt.(float64)
if ok {
fmt.Println(v)
} else {
fmt.Println("Failed without panicking!")
}

首先,声明myInt变量,该变量具有动态类型int和值123。然后使用类型断言测试两次myInt变量的接口类型 — 分别是int类型和float64类型。

由于myInt变量不包含float64值,因此类型断言myInt.(float64)执行时,如果没有恰当的处理,则会引发错误。因此在这种情况下,使用ok变量来判断类型断言是否成功,将使程序免于panic异常。

以下Go代码是assertion.go程序的第二部分:

i := myInt.(int)
fmt.Println("No cheking:", i)
j := myInt.(bool)
fmt.Println(j)
}

这里有两种类型的断言。第一个类型断言是成功的,因此不会有任何问题。但是,让我们进一步回顾一下这个特定类型的断言。变量i的类型为int,其值为123,存储在myInt中。因此由于int满足myInt接口,并且myInt接口不需要实现接口函数,所以myInt.(int)的值是一个int值。

然而第二个类型断言myInt.(bool)将触发panic异常,因为myInt的基础值不是布尔值(bool)。因此执行assertion.go将生成以下输出:

$ go run assertion.go
Success: 123
Failed without panicking!
No cheking: 123
panic: interface conversion: interface {} is int, not bool
goroutine 1 [running]:
main.main()
/Users/mtsouk/Desktop/masterGo/ch/ch7/code/assertion.go:25 +0x1d9
exit status 2

程序的执行结果明确的给出了触发panic异常的原因:interface{} is int, not bool

一般来说,在使用接口时,也应该使用类型断言。您马上会在useInterface.go程序中看到更多类型断言的使用案例。