空指针结构体与nil不深度相等吗?

huangapple go评论87阅读模式
英文:

Nil pointer to struct not deep equal to nil?

问题

如果我有一个包含类型为Anil指针的结构体,在使用reflect.DeepEqual检查该属性是否为nil时,结果将为false,这对我来说是奇怪的行为。

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)
// 输出: "O value: <nil>, is nil: false"

具体来说,我正在将一个JSON对象编组为一个结构体,我希望在相应的JSON结构不包含该属性时,测试特定属性是否为nil。如果reflect.DeepEqual不是正确的方法,我应该如何做到这一点?

英文:

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.

<!-- language: lang-go -->

type Container struct {
    O *Obj
}

type Obj struct {
    Message string
}

var c Container
eq := reflect.DeepEqual(c.O, nil)
fmt.Printf(&quot;O value: %v, is nil: %t&quot;, c.O, eq)
// Prints: &quot;O value: &lt;nil&gt;, is nil: false&quot;

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?

答案1

得分: 3

你传递给reflect.DeepEqual()的所有内容都被包装在一个interface{}值中(如果它还不是这样的话):

func DeepEqual(x, y interface{}) bool

将比较interface{}值,其中第一个参数值不是nil,只有包装在其中的值。

接口值表示为(type; value)对。你传递给reflect.DeepEqual()的第一个值是一个(type; value)对,即(*Obj, nil),第二个值是nil。它们不相等。第二个值缺少类型信息。

如果将其与“有类型的”nil进行比较,结果将为true

reflect.DeepEqual(c.O, (*Obj)(nil)) // 这是true

看看这个例子:

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)))

输出结果(在Go Playground上尝试):

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

参考这个问题以深入了解:

https://stackoverflow.com/questions/29138591/hiding-nil-values-understanding-why-golang-fails-here/29138676#29138676

如果你想检查非nil接口内部包装的值是否为nil,可以使用反射:reflect.Value.IsNil()

更多详情请参阅:https://stackoverflow.com/questions/43895862/why-interface-type-doesnt-provide-an-isnil-method/43896204#43896204

英文:

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(&quot;c.O:&quot;, c.O)
fmt.Println(&quot;c.O == nil:&quot;, c.O == nil)
fmt.Println(&quot;c.O deep equal to nil:&quot;, reflect.DeepEqual(c.O, nil))
fmt.Println(&quot;c.O deep equal to (*Obj)(nil):&quot;, reflect.DeepEqual(c.O, (*Obj)(nil)))

Output (try it on the Go Playground):

c.O: &lt;nil&gt;
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:

https://stackoverflow.com/questions/29138591/hiding-nil-values-understanding-why-golang-fails-here/29138676#29138676

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: https://stackoverflow.com/questions/43895862/why-interface-type-doesnt-provide-an-isnil-method/43896204#43896204

huangapple
  • 本文由 发表于 2017年7月4日 15:51:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/44900065.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定