Go“一个包含nil指针的接口不是nil接口”踩坑
最近在项目中踩了一个深坑——“Golang中一个包含nil指针的接口不是nil接口”,总结下分享出来,如果你不是很理解这句话,那推荐认真看下下面的示例代码,避免以后写代码时踩坑。 示例一先一起来看下这段代码,你感觉有没有问题呢? type IPeople interface { hello() } type People struct { } func (p *People) hello() { fmt.Println("github.com/meetbetter") } func errFunc1(in int) *People { if in == 0 { fmt.Println("importantFunc返回了一个nil") return nil } else { fmt.Println("importantFunc返回了一个非nil值") return &People{} } } func main() { var i IPeople in := 0 i = errFunc1(in) if i == nil { fmt.Println("哈,外部接收到也是nil") } else { fmt.Println("咦,外部接收到不是nil哦") fmt.Printf("%v,%Tn",i,i) } } 这段代码的执行结果是: importantFunc返回了一个nil 咦,外部接收到不是nil哦 <nil>,*main.People 可以看到在main函数中收到的返回值不是nil, 明明在errFunc1()函数中返回的是nil,到了main函数为什么收到的不是nil呢? 先来看看正确的处理接口返回值的方法,是直接将nil赋给interface: func rightFunc(in int) IPeople { if in == 0 { fmt.Println("importantFunc返回了一个nil") return nil } else { fmt.Println("importantFunc返回了一个非nil值") return &People{} } } 示例二下面的代码更清晰的证明了 type IPeople interface { hello() } type People struct { } func (p *People) hello() { fmt.Println("github.com/meetbetter") } //错误:将nil的people给空接口后接口就不为nil,因为interface中的value为nil但type不为nil func errFunc() *People { var p *People return p } //正确处理返回nil给接口的方式:直接将nil赋给interface func rightFunc() IPeople { var p *People return p } func main() { if errFunc() == nil { fmt.Println("对了哦,外部接收到也是nil") } else { fmt.Println("错了咦,外部接收到不是nil哦") } if rightFunc() == nil { fmt.Println("对了哦,外部接收到也是nil") } else { fmt.Println("错了咦,外部接收到不是nil哦") } } 输出结果: 对了哦,外部接收到也是nil 错了咦,外部接收到不是nil哦 interface底层实现下面的注释信息来自参考文章中,从interface底层实现可以看出iface比eface 中间多了一层itab结构, itab 存储_type信息和[]fun方法集,所以即使data指向了nil 并不代表interface 就是nil, 还要考虑_type信息。 type eface struct { //空接口 _type *_type //类型信息 data unsafe.Pointer //指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void*) } type iface struct { //带有方法的接口 tab *itab //存储type信息还有结构实现方法的集合 data unsafe.Pointer //指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void*) } type _type struct { size uintptr //类型大小 ptrdata uintptr //前缀持有所有指针的内存大小 hash uint32 //数据hash值 tflag tflag align uint8 //对齐 fieldalign uint8 //嵌入结构体时的对齐 kind uint8 //kind 有些枚举值kind等于0是无效的 alg *typeAlg //函数指针数组,类型实现的所有方法 gcdata *byte str nameOff ptrToThis typeOff } type itab struct { inter *interfacetype //接口类型 _type *_type //结构类型 link *itab bad int32 inhash int32 fun [1]uintptr //可变大小 方法集合 } 以上完整代码均整理在Github-跟着示例代码学Golang项目。 参考文章: "一个包含nil指针的接口不是nil接口"的讨论 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |