一个接口类型的变量 varI 中可以包含任何类型的值,必须有一种方式来检测它的 动态 类型,即运行时在变量中存储的值的实际类型。在执行过程中动态类型可能会有所不同,但是它总是可以分配给接口变量本身的类型。通常我们可以使用 类型断言 来测试在某个时刻 varI 是否包含类型 T 的值:

    1. v := varI.(T) // unchecked type assertion

    varI 必须是一个接口变量,否则编译器会报错:invalid type assertion: varI.(T) (non-interface type (type of varI) on left)

    类型断言可能是无效的,虽然编译器会尽力检查转换是否有效,但是它不可能预见所有的可能性。如果转换在程序运行时失败会导致错误发生。更安全的方式是使用以下形式来进行类型断言:

    1. if v, ok := varI.(T); ok { // checked type assertion
    2. Process(v)
    3. return
    4. }
    5. // varI is not of type T

    如果转换合法,vvarI 转换到类型 T 的值,ok 会是 true;否则 v 是类型 T 的零值,okfalse,也没有运行时错误发生。

    应该总是使用上面的方式来进行类型断言

    多数情况下,我们可能只是想在 if 中测试一下 ok 的值,此时使用以下的方法会是最方便的:

    1. if _, ok := varI.(T); ok {
    2. // ...
    3. }

    示例 11.4 type_interfaces.go

    1. package main
    2. import (
    3. "fmt"
    4. "math"
    5. )
    6. type Square struct {
    7. side float32
    8. }
    9. type Circle struct {
    10. radius float32
    11. }
    12. type Shaper interface {
    13. Area() float32
    14. }
    15. func main() {
    16. var areaIntf Shaper
    17. sq1 := new(Square)
    18. sq1.side = 5
    19. areaIntf = sq1
    20. // Is Square the type of areaIntf?
    21. if t, ok := areaIntf.(*Square); ok {
    22. fmt.Printf("The type of areaIntf is: %T\n", t)
    23. }
    24. if u, ok := areaIntf.(*Circle); ok {
    25. fmt.Printf("The type of areaIntf is: %T\n", u)
    26. } else {
    27. fmt.Println("areaIntf does not contain a variable of type Circle")
    28. }
    29. }
    30. func (sq *Square) Area() float32 {
    31. return sq.side * sq.side
    32. }
    33. func (ci *Circle) Area() float32 {
    34. return ci.radius * ci.radius * math.Pi
    35. }

    输出:

    1. The type of areaIntf is: *main.Square
    2. areaIntf does not contain a variable of type Circle

    程序行中定义了一个新类型 Circle,它也实现了 Shaper 接口。 t, ok := areaIntf.(*Square); ok 测试 areaIntf 里是否一个包含 ‘Square’ 类型的变量,结果是确定的;然后我们测试它是否包含一个 ‘Circle’ 类型的变量,结果是否定的。

    备注

    如果忽略 areaIntf.(*Square) 中的 * 号,会导致编译错误:impossible type assertion: Square does not implement Shaper (Area method has pointer receiver)