Go接口类型断言详解

如果你想学到更多实用知识。

可以关注我的公众号:【前端驿站Lite】,一个不止分享前端的地方 ᕦ( •̀∀•́)ᕤ

什么是断言

因为多态,一个接口可以被多个类型实现,在使用接口类型变量时,有时候需要确定这个变量具体的类型,这时就需要使用类型断言了。

在Go语言中,断言(Assertion)是一种用于判断接口类型的机制,将接口变量转换成另外一个接口或者另外一个类型,它允许我们在程序中判断一个接口的实际类型是否与我们预期的类型相同,以便进行相应的处理。

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

断言的语法形式为x.(T),其中x是一个接口类型的值T是一个具体的类型。这个语法表示我们要判断x的实际类型是否是T,类型断言会返回两个值,一个是实际转换后的值,另一个是指示转换是否成功的布尔值。

value, ok := interfaceValue.(interfaceType)

特别注意:断言只能用于接口类型

基本操作

// 基本格式
x.(T)
v := x.(T)
v, ok := x.(T)

类型断言的必要条件是x是接口类型,非接口类型的x不能做类型断言

var i int = 10
v := i.(int) //错误例子

T可以是非接口类型,如果想断言合法,则T应该实现x的接口。

T也可以是接口,则x的动态类型也应该实现接口T

var x interface{} = 7  // x 的动态类型为int, 值为 7
i := x.(int)           // i 的类型为 int, 值为 7
type I interface { m() }
var y I                 // y 为 I 接口类型变量
s := y.(string)        // 非法: string 没有实现接口 I (missing method m)
r := y.(io.Reader)     // y 如果实现了接口io.Reader和I的情况下, r的类型则为io.Reader

简单的例子: 如果类型 A 和类型 B 都实现了接口 I,那么你可以通过类型断言将类型 A 转换为类型 B。但如果类型 C 并不实现接口 I,那么将类型 A 转换为类型 C 是不合法的,会导致编译错误或运行时错误

类型选择

在 Go 语言中,类型选择(Type Switch)是一种多分支的语句,用于根据接口值的类型进行不同的处理。类型选择的语法如下:

switch interfaceValue.(type) {
    case type1:
        // 处理 type1 类型
    case type2:
        // 处理 type2 类型
        ...
    default:
        // 处理其他类型
}

其中,interfaceValue 表示接口值,type1 表示第一个类型,type2 表示第二个类型,default 表示其他类型。在每个分支中,我们可以根据类型进行不同的处理。

接口转换其他类型

如果自身是一个指针类型,那么被判断的类型也应该是指针类型。

func main() {

   // 创建结构体指针类型
   p1 := new(Hero)
   // Thanos := new(Demon)

   var fighter Fighter = p1

   // Fighter 接口 转换为 *Hero
   p2 := fighter.(*Hero)

   fmt.Printf("p1=%p\n", p1)
   fmt.Printf("p2=%p\n", p2)
   
}

实践

基本使用

比如:我们可以使用类型断言将一个 interface{} 类型转换为 int 类型:

func main() {
    var i interface{} = 10 // 空接口可以接收任意数据类型
    if v, ok := i.(int); ok {
        fmt.Printf("i is a int, value is %d\n", v)
    } else {
        fmt.Println("i is not a int")
    }
}

在上面的代码中,我们定义了一个 interface{} 变量 i,并将其赋值为 10。然后,我们使用类型断言将 i 转换为 int 类型,并判断类型转换是否成功。如果类型转换成功,我们就可以使用转换后的值 v

类型选择

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

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

进阶用法

package main

import "fmt"

type Animal interface {
	Sound()
}

type Dog struct{}

func (d Dog) Sound() {
	fmt.Println("Woof!")
}

type Cat struct{}

func (c Cat) Sound() {
	fmt.Println("Meow!")
}

func main() {
	animals := []Animal{Dog{}, Cat{}}

	for _, animal := range animals {
		// 判断接口类型是否是Dog
		if dog, ok := animal.(Dog); ok {
			dog.Sound()
		}

		// 判断接口类型是否是Cat
		if cat, ok := animal.(Cat); ok {
			cat.Sound()
		}
	}
}

在上面的代码中,我们定义了一个Animal接口,以及两个实现了Animal接口的类型DogCat。在main函数中,我们创建了一个包含DogCat实例的切片animals。然后,我们使用for range循环遍历切片中的每一个元素。

在循环体中,我们使用断言来判断当前元素的实际类型,并根据类型执行相应的操作。如果当前元素的实际类型是Dog,则将其转换为Dog类型并调用Sound方法;如果当前元素的实际类型是Cat,则将其转换为Cat类型并调用Sound方法。

总结:

断言是 Go 语言中非常重要的特性,可以帮助我们将接口类型转换为其他类型,并根据接口值的类型进行不同的处理。掌握断言的使用方法可以提高代码的灵活性和可维护性。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值