类型断言
个人理解
这个东西看了好久才看懂,然后还借鉴了一下其他的文章: Go 语言中的类型断言是什么?
虽然这个借鉴的文章没有讲全,讲透,但是让我理解go语言圣经里面写的内容起到了帮助
我的理解关键点是:
首先,x.(T), x必然是一个接口,接口有3个属性
- 接口动态类型
- 接口的动态值
- 接口的方法集合
具体类型的属性
- 类型
- 存储的对应类型的值
- 方法(可能没有方法,和类型共同决定满足哪些接口)
Go 语言数据类型包含基础类型和复合类型两大类。
基础数据类型包括:布尔型、整型、浮点型、复数型、字符型、字符串型、错误类型。
复合数据类型包括:指针、数组、切片、字典、通道、结构体、接口。
T取值:
- 然后T可以是具体的类型,判断是否x是否是这个类型,如果是,则把类型断言的结果是x的动态值(接口的属性),它的类型是T(具体类型的属性)
- 如果T是接口类型,则类型断言结果的接口的类型和接口动态值还是不变,值变化接口的方法集合(通过更大)—可以看后面的一小点小测试
x取值:
如果为nil,会panic,当然类型断言如果用了 _, ok = x.(T)
则会ok = false
var k io.Writer
_, ok := k.(io.ByteReader)
fmt.Println(k)
fmt.Println(ok)
// <nil>
// false
go语言圣经原文以及一小点测试
类型断言是一个使用在接口值上的操作。语法上它看起来像x.(T)被称为断言类型,这里x表示一个接口的类型和T表示一个类型。一个类型断言检查它操作对象的动态类型是否和断言的类型匹配。
这里有两种可能。第一种,如果断言的类型T是一个具体类型,然后类型断言检查x的动态类型是否和T相同。如果这个检查成功了,类型断言的结果是x的动态值,当然它的类型是T。换句话说,具体类型的类型断言从它的操作对象中获得具体的值。如果检查失败,接下来这个操作会抛出panic。例如:
var w io.Writer
w = os.Stdout
f := w.(*os.File) // success: f == os.Stdout
c := w.(*bytes.Buffer) // panic: interface holds *os.File, not *bytes.Buffer
第二种,如果相反地断言的类型T是一个接口类型,然后类型断言检查是否x的动态类型满足T。如果这个检查成功了,动态值没有获取到;这个结果仍然是一个有相同动态类型和值部分的接口值,但是结果为类型T。换句话说,对一个接口类型的类型断言改变了类型的表述方式,改变了可以获取的方法集合(通常更大),但是它保留了接口值内部的动态类型和值的部分。
在下面的第一个类型断言后,w和rw都持有os.Stdout,因此它们都有一个动态类型*os.File,但是变量w是一个io.Writer类型,只对外公开了文件的Write方法,而rw变量还公开了它的Read方法。
var w io.Writer
w = os.Stdout
fmt.Printf("%v %T\n", w, w)
rw := w.(io.ReadWriter) // success: *os.File has both Read and Write
fmt.Printf("%v %T\n", w, w)
fmt.Printf("%v %T\n", rw, rw)
w = new(ByteCounter)
rw = w.(io.ReadWriter) // panic: *ByteCounter has no Read method
⚡ 06/10|10:26:33 test go run str.go
&{0xc0000780c0} *os.File
&{0xc0000780c0} *os.File
&{0xc0000780c0} *os.File