0

First let's consider the following:

func process(body io.Reader) {
    fmt.Printf("body == nil ? %+v\n", body == nil)
}

func main() {
    var body *bytes.Buffer
    fmt.Printf("body == nil ? %+v\n", body == nil)
    process(body)
    process(nil)
}

And here's the output:

body == nil ? true
body == nil ? false  // Did you get this right?
body == nil ? true

Another example:

type Container struct {
    Reader io.Reader
}

func processContainer(container Container) {
    fmt.Printf("container.Reader == nil ? %+v\n", container.Reader == nil)
}

func main() {
    var body *bytes.Buffer
    processContainer(Container{Reader: body})
    processContainer(Container{Reader: nil})
}

Output:

container.Reader == nil ? false // Did you get this right?
container.Reader == nil ? true

The explanation for this is at https://golang.org/doc/faq#nil_error.

A naive solution is to make the == nil test just return true if the interface object contains nil value. But this would violate transitivity of ==, as it would assert two objects with nil value but different interface types true under ==.

However, I wonder if there should be an IsNil() method on all interface types, which would solve this issue?

Another example, this line from Go http client, can catch you unexpectedly:

https://github.com/golang/go/blob/master/src/net/http/client.go#L545

So if you call it like this

var body *bytes.Buffer
http.NewRequest(method, path, body)

You'll get a nil pointer exception, even though, by the look of the source code, this shouldn't happen.

Edit

Sorry I referenced the wrong line of the Go http source, now corrected. But the example still holds.

Edit 2

I've highlighted my question to make it clear what I'm asking.

icza
  • 389,944
  • 63
  • 907
  • 827
stackoverflower
  • 3,885
  • 10
  • 47
  • 71
  • Please note this question is about why "IsNil()" isn't provided in Go as a method. The "duplicated" question doesn't go this way. – stackoverflower May 10 '17 at 14:54
  • You can use `== nil` on all interface values to test if they are equal. The confusion in your case comes from that inside `process()` you check if the _interface_ value is `nil`, while in your `main()` function you check the **non-interface, pointer** value. The interface value is automatically, implicitly created when the pointer is passed to the function. – icza May 10 '17 at 14:54

3 Answers3

5

First read this related question: Hiding nil values, understanding why golang fails here

You can check if the interface value itself is nil by comparing it to nil.

If you want to check if the value wrapped inside a non-nil interface is nil, you can use reflection: reflect.Value.IsNil().

See this modified example:

func process(body io.Reader) {
    fmt.Printf("process(): body == nil ? %t\n", body == nil)
    if body != nil {
        fmt.Println("\tINSIDE IsNil():", reflect.ValueOf(body).IsNil())
    }
}

func main() {
    var body *bytes.Buffer
    fmt.Printf("main(): body == nil ? %t\n", body == nil)
    process(body)
    process(nil)
    process(&bytes.Buffer{})
}

Output (try it on the Go Playground):

main(): body == nil ? true
process(): body == nil ? false
    INSIDE IsNil(): true
process(): body == nil ? true
process(): body == nil ? false
    INSIDE IsNil(): false

If you want a "unified" IsNil() function which tells if either is nil:

func IsNil(i interface{}) bool {
    return i == nil || reflect.ValueOf(i).IsNil()
}
Community
  • 1
  • 1
icza
  • 389,944
  • 63
  • 907
  • 827
2

Here's a function that reports if an interface contains any nil. Note that reflect.Value.IsNil() panics if the type doesn't have a nil value, so some checking on the kind must be done before calling it.

func isNil(x interface{}) bool {
    v := reflect.ValueOf(x)
    switch v.Kind() {
    case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.UnsafePointer, reflect.Slice:
        return v.IsNil()
    default:
        return false
    }
}

Here's a working example in the playground: https://play.golang.org/p/RHzu3VVj4Zd

Paul Hankin
  • 54,811
  • 11
  • 92
  • 118
-1

The following is clearly based on Paul Hankin's answer, a tad of what icza wrote and the sources of reflect/value.go where func (v Value) IsNil() bool is defined. Do not trust the source, I am a newbie taking advantage of Cunningham's law! I would have just commented but I do not even have 50 points (-:

func isNil(x interface{}) bool {
    if x == nil {                                 // nil with no type.
        return true
    }
    v := reflect.ValueOf(x)
    switch v.Kind() {                             // reflect.Invalid for nil
    case reflect.Chan, reflect.Func, reflect.Map, // 1st case of v.isNil
        reflect.Ptr, reflect.UnsafePointer,       
        reflect.Interface, reflect.Slice:         // 2nd case of v.isNil
        return v.IsNil()
    default:
        return false
    }
}