Go "contains a pointer to the interface is not nil nil Interface" hit pit

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 *Peoplethen be *Peopleassigned to the interface, *Peopleitself 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.Peoplerather 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

Guess you like

Origin www.cnblogs.com/CodeWithTxT/p/11297300.html