变量的 T 和 V , _type 是这个变量对应的类型 , data 是这个变量的值 。在之前的赋值测试中 , 通过 reflect.TypeOf 与 reflect.ValueOf 方法获取到的信息也分别来自这两个字段 。
这里的 hash 字段和 _type 中存的 hash 字段是完全一致的 , 这么做的目的是为了类型断言 。
fun 是一个函数指针 , 它指向的是具体类型的函数方法 , 在这个指针对应内存地址的后面依次存储了多个方法 , 利用指针偏移便可以找到它们 。
再来看看 interfacetype 的结构:
type interfacetype struct { typ_type pkgpath name mhdr[]imethod}这其中也有一个 _type 字段 , 来表示 interface 变量的初始类型 。
看到这里 , 之前的疑问便开始清晰起来 , 一个 interface 变量实际上有两个类型 , 一个是初始化时赋值时对应的 interface 类型 , 一个是赋值具体对象时 , 对象的实际类型 。
了解了这些之后 , 我们再来看一下之前的例子:
txn, err := startTx()这里先对 err 进行初始化赋值 , 此时 , 它的 itab.inter.typ 对应的类型信息就是 erroritab._type 仍为 nil 。
err = txn.doUpdate()当对 err 进行重新赋值时 , err 的 itab._type 字段会被赋值成 *CustomizedError , 所以此时 , err 变量实际上是一个 itab.inter.typ 为 error , 但实际类型为 *CustomizedError , 值为 nil 的接口变量 。
把一个具体类型变量与 nil 比较时 , 只需要判断其 value 是否为 nil 即可 , 而把一个接口类型的变量与 nil 进行比较时 , 还需要判断其类型 itab._type 是否为nil 。
如果想实际看看被赋值后 err 对应的 iface 结构 , 可以把 iface 相关的结构体都复制到同一个包下 , 然后通过 unsafe.Pointer 进行类型强转 , 就可以通过打断点的方式来查看了 。
func TestErr(t *testing.T) { txn, err := startTx() fmt.Println(reflect.TypeOf(err), reflect.ValueOf(err)) if err != nil {log.Fatalf("err starting tx: %v", err) } p := (*iface)(unsafe.Pointer(&err)) fmt.Println(p.data) if err = txn.doUpdate(); err != nil {fmt.Println(reflect.TypeOf(err), reflect.ValueOf(err))p := (*iface)(unsafe.Pointer(&err))fmt.Println(p.data)log.Fatalf("err updating: %v", err) } if err = txn.commit(); err != nil {log.Fatalf("err committing: %v", err) } fmt.Println("success!")}
![[Go疑难杂症]为什么nil不等于nil](http://shimg.jingyanzongjie.com/230726/224053I59-1.png)
文章插图
补充说明一下 , 这里的
inter.typ.kind 表示的是变量的基本类型 , 其值对应 runtime 包下的枚举 。const ( kindBool = 1 + iota kindInt kindInt8 kindInt16 kindInt32 kindInt64 kindUint kindUint8 kindUint16 kindUint32 kindUint64 kindUintptr kindFloat32 kindFloat64 kindComplex64 kindComplex128 kindArray kindChan kindFunc kindInterface kindMap kindPtr kindSlice kindString kindStruct kindUnsafePointer kindDirectIface = 1 << 5 kindGCProg= 1 << 6 kindMask= (1 << 5) - 1)比如上图中所示的 kind = 20 对应的类型就是
经验总结扩展阅读
- 十二星座的爱情为什么总在十万八千里
- 菊花茶泡了为什么会变绿
- 新鲜花椒冷冻为什么要放水
- 贵州为什么叫黔
- 电脑?号怎么打出来(电脑为什么打不出来字)
- 岩茶第一泡为什么叫还魂汤
- 网上买的鲜花要醒花多久 网购鲜花为什么要醒花
- 网上买的鲜花回来怎么泡好 网购鲜花为什么要醒花
- 西瓜为什么叫西瓜呢
- 床上为什么会有小虫子
