Go语言之类型断言


一、基础

什么是类型断言呢?

  举个例子,我们在之前的Usb接口案例中,假如Phone这个结构体除了实现接口的方法外,它还有自己定义的一个单独方法,但是Carema没有,那么当传入到Computer的use方法中就需要进行类型判断,如果是Phone结构体类型还需要执行额外的方法。

所以类型断言是由于接口不知道具体类型,如果要转成具体类型,就需要使用类型断言。

package main

import "fmt"

func main() {

    var i interface{}

    var a float64 = 6.32
    i = a //空接口可以接收任意数据类型
    // 使用类型断言
    b := i.(float64)
    fmt.Printf("b的类型为%T 值为%v", b, b) // b的类型为float64 值为6.32

}

在进行类型断言时,如果类型不匹配就会报panic错误,因此在进行类型断言时,确保原来的空接口指向的就是断言的类型。当然你也可以通过检测机制,就是使用返回值来进行判断,避免panic错误的产生。

package main

import "fmt"

func main() {

    var i interface{}

    var a float64 = 6.32
    i = a //空接口可以接收任意数据类型
    // 使用类型断言,检测机制,避免panic错误
    b, flag := i.(float64)
    if flag {
        fmt.Printf("b的类型为%T 值为%v", b, b) // b的类型为float64 值为6.32
    } else {
        fmt.Println("类型转换失败")
    }

}

二、最佳实践

1、案例一

 如果在Phone结构体中额外增加talking方法,那么在Computer中的use方法中就需要使用断言来判断了。

package main

import "fmt"

// 定义一个接口
type Usb interface {
    // 声明两个未实现的方法
    start()
    stop()
}

// 声明一个Phone的结构体
type Phone struct {
}

// Phone结构体变量接口实现方法
func (phone Phone) start() {
    fmt.Println("手机开始工作...")
}

func (phone Phone) stop() {
    fmt.Println("手机结束工作...")
}

// Phone结构体变量中额外的方法
func (phone Phone) talking() {
    fmt.Println("正在通话中...")
}

// 声明一个Camera的结构体
type Camera struct {
}

// Camera结构体变量接口实现方法
func (camera Camera) start() {
    fmt.Println("相机开始工作...")
}

func (camera Camera) stop() {
    fmt.Println("相机结束工作...")
}

// 声明一个Computer结构体
type Computer struct {
}

// usb会自动根据传递过来的来判断是phone还是camera然后调用对应的结构体变量中实现的方法
func (computer Computer) use(usb Usb) {
    usb.start()
    usb.stop()
    // 使用断言
    phone, flag := usb.(Phone)
    if flag {
        phone.talking()
    }
}

func main() {
    // 创建结构体变量
    computer := Computer{}

    phone := Phone{}
    camera := Camera{}

    computer.use(phone)
    computer.use(camera)

}

/*
手机开始工作...
手机结束工作...
正在通话中...
相机开始工作...
相机结束工作...
*/

2、案例二

类型判断,写一个函数来循环判断传入的参数类型。

package main

import "fmt"

func JudgeType(items ...interface{}) {
    for index, value := range items {
        switch value.(type) {
        case bool:
            fmt.Printf("第%v个参数时bool类型,值为%v\n", index, value)
        case float32:
            fmt.Printf("第%v个参数时float32类型,值为%v\n", index, value)
        case float64:
            fmt.Printf("第%v个参数时float64类型,值为%v\n", index, value)
        case int:
            fmt.Printf("第%v个参数时int类型,值为%v\n", index, value)
        case string:
            fmt.Printf("第%v个参数时string类型,值为%v\n", index, value)
        default:
            fmt.Printf("第%v个参数类型不确定,值为%v\n", index, value)
        }

    }
}

func main() {
    var a int = 10
    var b string = "happy"
    var c float32 = 3.21
    JudgeType(a, b, c)
}