变量的 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
对应的类型信息就是 error
itab._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
对应的类型就是
经验总结扩展阅读
- 十二星座的爱情为什么总在十万八千里
- 菊花茶泡了为什么会变绿
- 新鲜花椒冷冻为什么要放水
- 贵州为什么叫黔
- 电脑?号怎么打出来(电脑为什么打不出来字)
- 岩茶第一泡为什么叫还魂汤
- 网上买的鲜花要醒花多久 网购鲜花为什么要醒花
- 网上买的鲜花回来怎么泡好 网购鲜花为什么要醒花
- 西瓜为什么叫西瓜呢
- 床上为什么会有小虫子