If you have any questions or suggestions, please contact us in time. My official account is “Brain fried Fish”, GitHub address: github.com/eddycjy.

Hello, I’m fried fish.

A few days ago, I saw a friend in the reader exchange group, and I had a big doubt about the use of interface.

Coincidentally, I also saw some friends on the Internet who were asked during the Go interview:

I’m sharing it today to help you avoid this pit.

Example a

For the first example, the following code:

func main(a) {
    var v interface{}
    v = (*int) (nil)
    fmt.Println(v == nil)}Copy the code

What do you think the output is?

The answer is:

false
Copy the code

Why not true. I’ve already forced it to nil. Is there a problem with the Go compiler?

Example 2

For the second example, the following code:

func main(a) {
    var data *byte
    var in interface{}

    fmt.Println(data, data == nil)
    fmt.Println(in, in == nil)

    in = data
    fmt.Println(in, in == nil)}Copy the code

What do you think the output is?

The answer is:

<nil> true
<nil> true
<nil> false
Copy the code

And that’s even more surprising, because the data and in variables that we just declared, they actually output nil, and they’re judged to be true.

How can the world change as soon as I assign the variable data to the variable in? The output is still nil, but the determination is false.

The result is similar to the first example above, which is amazing.

why

The fundamental reason interface is different is that interface is not a pointer type, although it looks like one, which can be misleading.

We drill down to the interface, which has two types of data structures:

  • runtime.efaceStruct: Represents an empty interface that contains no methods, also known as an empty interface.
  • runtime.ifaceStruct: Represents the interface that contains the method.

Take a look at the corresponding underlying data structures for both:

type eface struct {
    _type *_type
    data  unsafe.Pointer
}

type iface struct {
    tab  *itab
    data unsafe.Pointer
}
Copy the code

You’ll see that interfaces are not just values, but types and values.

Therefore, the traditional perception of nil is that this nil is not that nil, and the nil judgment of the interface can only be true if the type and value are both nil.

The solution

It’s not so much a solution as a euphemistic solution. One way to do this without changing the type is to use Reflection as follows:

func main(a) {
    var data *byte
    var in interface{}

    in = data
    fmt.Println(IsNil(in))
}

func IsNil(i interface{}) bool {
    vi := reflect.ValueOf(i)
    if vi.Kind() == reflect.Ptr {
        return vi.IsNil()
    }
    return false
}
Copy the code

Nil values are evaluated using reflection. There is special processing for interface types in reflection. The final output is true.

Otherwise, change the program logic, for example:

  • Nil for the value, and returns to the interface setting.
  • Return the specific value type instead of interface.

conclusion

The Go interface is one of the most commonly used types in the Go language. = nil is easy to step in.

If you want to know more about interface, you can take a look at my in-depth analysis of this article: “A Thorough understanding of the Go language decryption interface”.

Have you ever stepped on or encountered any “pits” related to interface? Feel free to share in the comments below. All together!

My official account

Share Go language, micro service architecture and strange system design, welcome to pay attention to my public number and I exchange and communication.

The best relationship is mutual achievement. Your praise is the biggest motivation for the creation of fried fish. Thank you for your support.