Go接口类型断言详解

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

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

什么是断言

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

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

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

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

go 复制代码
value, ok := interfaceValue.(interfaceType)

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

基本操作

go 复制代码
// 基本格式
x.(T)
v := x.(T)
v, ok := x.(T)

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

go 复制代码
var i int = 10
v := i.(int) //错误例子

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

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

go 复制代码
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)是一种多分支的语句,用于根据接口值的类型进行不同的处理。类型选择的语法如下:

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

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

接口转换其他类型

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

go 复制代码
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 类型:

go 复制代码
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

类型选择

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

go 复制代码
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)
}

进阶用法

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

完结撒花🎉🎉🎉,你又进步了一点点。

朋友,如果觉得本文章对你有帮助,可以留个赞👍再走嘛。

赠人玫瑰手留余香!先谢谢啦 ᕦ( •̀∀•́)ᕤ

相关推荐
逸风尊者2 分钟前
开发可掌握的知识:推荐系统
java·后端·算法
Violet_YSWY6 分钟前
阿里巴巴状态码
后端
灵魂猎手11 分钟前
Antrl4 入门 —— 使用Antrl4实现一个表达式计算器
java·后端
moxiaoran575321 分钟前
Go语言的递归函数
开发语言·后端·golang
IT 行者1 小时前
Spring Security 7.0 新特性详解
java·后端·spring
华仔啊1 小时前
Java 的金额计算用 long 还是 BigDecimal?资深程序员这样选
java·后端
12344521 小时前
【MCP入门篇】从0到1教你搭建MCP服务
后端·mcp
okseekw1 小时前
Java多线程开发实战:解锁线程安全与性能优化的关键技术
java·后端
HuangYongbiao1 小时前
NestJS 架构设计系列:应用服务与领域服务的区别
后端·架构
技术不打烊1 小时前
MySQL主从延迟飙升?元数据锁可能是“真凶”
后端