4

If I have a struct containing a nil pointer of type A, using reflect.DeepEqual to check if that property is nil will result in false, which strikes me as odd behaviour.

type Container struct {
    O *Obj
}

type Obj struct {
    Message string
}

var c Container
eq := reflect.DeepEqual(c.O, nil)
fmt.Printf("O value: %v, is nil: %t", c.O, eq)
// Prints: "O value: <nil>, is nil: false"

Specifically, I am marshaling a JSON object into a struct, where I would like to test that a specific property is nil when the corresponding JSON structure does not contain it. If reflect.DeepEqual is not the way to go, how should I do this?

icza
  • 389,944
  • 63
  • 907
  • 827
Sander
  • 1,183
  • 12
  • 27
  • You are right .. let look at documentation: https://golang.org/pkg/reflect/#DeepEqual . At first paragraph is answer to your question - Values of distinct types are never deeply equal. And rest of the answer is here https://golang.org/doc/faq#nil_error – lofcek Jul 04 '17 at 08:07

1 Answers1

3

Everything you pass to reflect.DeepEqual() is wrapped in an interface{} value (if it's not already that):

func DeepEqual(x, y interface{}) bool

interface{} values will be compared, where the first parameter value is not nil, only the value wrapped in it.

An interface value is represented as a (type; value) pair. The first value you pass to reflect.DeepEqual() is a pair of (type; value) being (*Obj, nil), and the 2nd value is nil. They are not equal. The second value lacks type information.

If you compare it to a "typed" nil, it will be true:

reflect.DeepEqual(c.O, (*Obj)(nil)) // This is true

See this example:

fmt.Println("c.O:", c.O)
fmt.Println("c.O == nil:", c.O == nil)
fmt.Println("c.O deep equal to nil:", reflect.DeepEqual(c.O, nil))
fmt.Println("c.O deep equal to (*Obj)(nil):", reflect.DeepEqual(c.O, (*Obj)(nil)))

Output (try it on the Go Playground):

c.O: <nil>
c.O == nil: true
c.O deep equal to nil: false
c.O deep equal to (*Obj)(nil): true

See this question for a deeper insight:

Hiding nil values, understanding why golang fails here

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

For more details see: Why interface type doesn't provide an "IsNil" method?

icza
  • 389,944
  • 63
  • 907
  • 827