Michael Whatcott
Michael Whatcott

Reputation: 5955

nil slice when passed as interface is not nil! Why? (golang)

See this playground: http://play.golang.org/p/nWHmlw1W01

package main

import "fmt"

func main() {
    var i []int = nil
    yes(i) // output: true
    no(i)  // output: false
}

func yes(thing []int) {
    fmt.Println(thing == nil)
}

func no(thing interface{}) {
    fmt.Println(thing == nil)
}

Why the difference in output between the two functions?

Upvotes: 14

Views: 2847

Answers (2)

Serid
Serid

Reputation: 361

To add to @justinas' answer, if you need to compare the value inside the interface{} value, you can use reflect.ValueOf.IsNil() method which would report if value inside the interface{} is nil.

func main() {
    var a []int = nil
    var ai interface{} = a

    r1 := a == nil // true
    r2 := ai == nil // false, interface is not nil

    vo := reflect.ValueOf(ai).IsNil() // true, value inside interface is nil!
}

Upvotes: 1

justinas
justinas

Reputation: 6857

Admittedly, it's somewhat of a quirk, but there's an explanation for it.

Imagine an interface{} variable as a struct composed of two fields: one is the type and another is the data. ([]int and nil). Actually, it looks just like that in the Go runtime.

struct Iface                                                                                                                   
{                                                                                                                              
    Itab*   tab;                                                                                                               
    void*   data;                                                                                                              
};   

When you pass your nil slice to yes, only nil is passed as the value, so your comparison boils down to nil == nil.

Meanwhile, calling no automatically wraps your variable in an interface{} type and the call becomes something akin to no(interface{[]int, nil}). So the comparison in no could be seen as interface{[]int, nil} == nil, which turns out to be false in go.

The issue is actually explained in the Go FAQ.

Upvotes: 18

Related Questions