Ric*_*kyA 5 struct pointers go
我有一个嵌套的结构。这些由json解组器构造。
但是,此结构中的某些字段是'omitifempty'的,因此我在op末尾使用的结构可以在各个地方使用nill。
示例(真正的东西嵌套得更深,很大:400行结构):
package main
import "fmt"
type Foo struct {
Foo string
Bar *Bar
}
type Bar struct {
Bar string
Baz *Baz
}
type Baz struct {
Baz string
}
func main() {
f1 := Foo{Foo: "f1"}
f2 := Foo{Foo: "f2", Bar: &Bar{Bar: "br2"}}
f3 := Foo{Foo: "f3", Bar: &Bar{Bar: "br3", Baz: &Baz{Baz: "bz3"}}}
fmt.Println(f3.Bar.Baz.Baz) //-> bz3
fmt.Println(f2.Bar.Baz.Baz) //-> panic: runtime error: invalid memory address or nil pointer dereference
fmt.Println(f1.Bar.Baz.Baz) //-> panic: runtime error: invalid memory address or nil pointer dereference
//so far so good, but
//is there a more generic way to do this kind of testing?
if f2.Bar != nil && f2.Bar.Baz != nil {
fmt.Println(f2.Bar.Baz.Baz)
} else {
fmt.Println("something nil")
}
}
Run Code Online (Sandbox Code Playgroud)
问题是是否有更通用的方法来测试参考树中的某个节点是否为nil?我需要获得很多不同的项目,而编写所有这些if语句将很痛苦。哦,速度值得关注。
icz*_*cza 12
处理它的一种优雅方式(在我看来)是将 getter 添加到用作指针的结构中。这种“技术”也被protobuf生成的 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
}
Run Code Online (Sandbox Code Playgroud)
带有指针接收器的方法的好处是你可以用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")
}
Run Code Online (Sandbox Code Playgroud)
在Go Playground上试一试。