menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right All_wiki chevron_right the-way-to-go_ZH_CN chevron_right eBook chevron_right 11.3.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    11.3.md
    3 KB / 2024-07-16 23:14:27
        # 11.3 类型断言:如何检测和转换接口变量的类型
    
    一个接口类型的变量 `varI` 中可以包含任何类型的值,必须有一种方式来检测它的 **动态** 类型,即运行时在变量中存储的值的实际类型。在执行过程中动态类型可能会有所不同,但是它总是可以分配给接口变量本身的类型。通常我们可以使用 **类型断言** 来测试在某个时刻 `varI` 是否包含类型 `T` 的值:
    
    ```go
    v := varI.(T)       // unchecked type assertion
    ```
    
    **`varI` 必须是一个接口变量**,否则编译器会报错:`invalid type assertion: varI.(T) (non-interface type (type of varI) on left)` 。
    
    类型断言可能是无效的,虽然编译器会尽力检查转换是否有效,但是它不可能预见所有的可能性。如果转换在程序运行时失败会导致错误发生。更安全的方式是使用以下形式来进行类型断言:
    
    ```go
    if v, ok := varI.(T); ok {  // checked type assertion
        Process(v)
        return
    }
    // varI is not of type T
    ```
    
    如果转换合法,`v` 是 `varI` 转换到类型 `T` 的值,`ok` 会是 `true`;否则 `v` 是类型 `T` 的零值,`ok` 是 `false`,也没有运行时错误发生。
    
    **应该总是使用上面的方式来进行类型断言**。
    
    多数情况下,我们可能只是想在 `if` 中测试一下 `ok` 的值,此时使用以下的方法会是最方便的:
    
    ```go
    if _, ok := varI.(T); ok {
        // ...
    }
    ```
    
    示例 11.4 [type_interfaces.go](examples/chapter_11/type_interfaces.go):
    
    ```go
    package main
    
    import (
    	"fmt"
    	"math"
    )
    
    type Square struct {
    	side float32
    }
    
    type Circle struct {
    	radius float32
    }
    
    type Shaper interface {
    	Area() float32
    }
    
    func main() {
    	var areaIntf Shaper
    	sq1 := new(Square)
    	sq1.side = 5
    
    	areaIntf = sq1
    	// Is Square the type of areaIntf?
    	if t, ok := areaIntf.(*Square); ok {
    		fmt.Printf("The type of areaIntf is: %T\n", t)
    	}
    	if u, ok := areaIntf.(*Circle); ok {
    		fmt.Printf("The type of areaIntf is: %T\n", u)
    	} else {
    		fmt.Println("areaIntf does not contain a variable of type Circle")
    	}
    }
    
    func (sq *Square) Area() float32 {
    	return sq.side * sq.side
    }
    
    func (ci *Circle) Area() float32 {
    	return ci.radius * ci.radius * math.Pi
    }
    ```
    
    输出:
    
        The type of areaIntf is: *main.Square
        areaIntf does not contain a variable of type Circle
    
    程序中定义了一个新类型 `Circle`,它也实现了 `Shaper` 接口。 `if t, ok := areaIntf.(*Square); ok` 测试 `areaIntf` 里是否有一个包含 `*Square` 类型的变量,结果是确定的;然后我们测试它是否包含一个 `*Circle` 类型的变量,结果是否定的。
    
    **备注**
    
    如果忽略 `areaIntf.(*Square)` 中的 `*` 号,会导致编译错误:`impossible type assertion: Square does not implement Shaper (Area method has pointer receiver)`。
    
    ## 链接
    
    - [目录](directory.md)
    - 上一节:[接口嵌套接口](11.2.md)
    - 下一节:[类型判断:type-switch](11.4.md)
    
    
    links
    file_download