Pointers 嵌套结构中零值的测试

Pointers 嵌套结构中零值的测试,pointers,go,struct,Pointers,Go,Struct,我在go中有一个深度嵌套的结构。它们由json解组器构造 然而,这个结构中有相当多的字段是“ommitifempty”,所以我在op的结尾使用了一个结构,该结构可以在不同的地方使用nill 示例(真实的东西嵌套得更深,而且更大:400行结构): 问题是,是否有更通用的方法来测试引用树中的某个节点是否为零?我需要得到很多不同的项目,这将是一个痛苦的写所有这些如果语句。 哦,速度是个问题。如果您想避免“”(反射,作为测试任何结构的字段的“通用”方法,有点像“”,或者在:它比较慢),最可靠的方法是在F

我在go中有一个深度嵌套的结构。它们由json解组器构造

然而,这个结构中有相当多的字段是“ommitifempty”,所以我在op的结尾使用了一个结构,该结构可以在不同的地方使用nill

示例(真实的东西嵌套得更深,而且更大:400行结构):

问题是,是否有更通用的方法来测试引用树中的某个节点是否为零?我需要得到很多不同的项目,这将是一个痛苦的写所有这些如果语句。 哦,速度是个问题。

如果您想避免“”(反射,作为测试任何
结构的字段的“通用”方法,有点像“”,或者在:它比较慢),最可靠的方法是在
Foo
上实现方法,以便返回正确的值

func (foo *Foo) BarBaz() string {
    if f2.Bar != nil && f2.Bar.Baz != nil {
        return f2.Bar.Baz.Baz
    } else {
        fmt.Println("something nil")
        return "" // for example
    } 
}
如果有很多这样的函数需要编写,也许command可以帮助生成大部分函数。

一种优雅的处理方法(在我看来)是向用作指针的结构添加getter。生成的Go代码也使用这种“技术”,它允许方法调用的自然链接,而不必担心由于
nil
指针而导致的运行时死机

在您的示例中,
Bar
Baz
结构用作指针,因此使用getter来武装它们。重点是使用指针接收器添加方法,首先必须检查接收器是否为
nil
。如果是,则返回结果类型的零值。如果不是,则继续返回结构的字段:

func (b *Bar) GetBaz() *Baz {
    if b == nil {
        return nil
    }
    return b.Baz
}

func (b *Baz) GetBaz() string {
    if b == nil {
        return ""
    }
    return b.Baz
}
使用指针接收器的方法的好处是,您可以使用
nil
接收器调用它们。它不会引起运行时恐慌,除非您尝试引用它们的字段,而我们没有,这就是为什么我们首先检查接收器是否为
nil
(最终,接收器充当正常参数–将
nil
作为指针参数传递决不是错误)

有了上述getter,使用就简化为这样,并且在以下任何示例中都不会发生运行时死机:

fmt.Println(f3.Bar.GetBaz().GetBaz()) // naturally no panic
fmt.Println(f2.Bar.GetBaz().GetBaz()) // No panic
fmt.Println(f1.Bar.GetBaz().GetBaz()) // No panic

if baz := f2.Bar.GetBaz(); baz != nil {
    fmt.Println(baz.GetBaz())
} else {
    fmt.Println("something nil")
}

在上试试。

嗯,reflect很好而且通用,但是要慢一点才有用。我错过了围棋,看起来很有趣。将会深入。@RickyA是的,每次你看到:“写这些东西会很痛苦…
”,你现在有了go 1.4选项
go generate
:非常好的建议(投票)。我以前在一场关于Go的空安全运算符的辩论中看到过这一点:我将接受的答案换成了这个答案,因为我最终使用了很多访问器函数。不过,我可以通过使用您的
self==nil
测试进行改进。我发现了codegen的这种方法的实现:
fmt.Println(f3.Bar.GetBaz().GetBaz()) // naturally no panic
fmt.Println(f2.Bar.GetBaz().GetBaz()) // No panic
fmt.Println(f1.Bar.GetBaz().GetBaz()) // No panic

if baz := f2.Bar.GetBaz(); baz != nil {
    fmt.Println(baz.GetBaz())
} else {
    fmt.Println("something nil")
}