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