Recently stepped into a deep pit in the project - "Golang contains a pointer to the interface is not nil nil Interface" to share out under summary, if you're not quite understand this sentence, it is recommended that a serious look at the following example code, avoid after stepping pit when writing code.
Examples of a
First look at the code together, you feel there is no problem with it?
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, %T\n", i, i)
}
}
The results of this code is:
importantFunc返回了一个nil
咦,外部接收到不是nil哦
<nil>, *main.People
Can be seen in the main function returns the value received is not nil, obviously in errFunc1 () function returns nil, the main function to why it is not nil received?
This is because: assigning to nil *People
then be *People
assigned to the interface, *People
itself is nil pointer is pointing, but only in the interface is nil, but the type of information interface which is assigned to the interface *main.People
rather than nil, so this interface is not nil.
Yes, golang the interface type comprising two pieces of information - type information and value information, only interface types are combined value is nil nil only for the interface, may analyze the underlying implementation interface see later source.
Let's look at the right way to deal with the interface return value is assigned directly to nil interface:
func rightFunc(in int) IPeople {
if in == 0 {
fmt.Println("importantFunc返回了一个nil")
return nil
} else {
fmt.Println("importantFunc返回了一个非nil值")
return &People{}
}
}
Example Two
The following code demonstrates clearer 一个包含nil指针的接口不是nil接口
conclusions:
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哦")
}
}
Output:
对了哦,外部接收到也是nil
错了咦,外部接收到不是nil哦
interface underlying implementation
The following annotation information from the referenced article, it can be seen from the underlying implementation interface iface more than the intermediate layer structure itab eFace, itab _type information storage and [] Fun methodologies, even if the data point does not represent the interface is nil nil, but also consider _type information.
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 //可变大小 方法集合
}
More complete code are finishing follow the example code to learn Golang project Github- .
Reference article:
golang first pit
Discuss "contains a pointer interface is not nil nil Interface" in