测试嵌套结构中的 nil 值 [英] Test for nil values in nested stucts

查看:31
本文介绍了测试嵌套结构中的 nil 值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 go 中有一个深度嵌套的结构.这些是由 json unmarshaller 构建的.

I have a deeply nested struct in go. These are constructed by a json unmarshaller.

然而,这个结构中的相当多的字段是省略"的,所以我以一个可以在不同地方有 nill 的结构结束 op.

Quite some fields in this struct are however 'omitifempty' so I end op with a struct that can have nills in various places.

示例(实际嵌套更深,而且很大:400 行结构):

Example (the real thing is even deeper nested, and big: 400 lines of structs):

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

问题是是否有更通用的方法来测试参考树中的某个节点是否为零?我需要得到很多不同的项目,编写所有这些 if 语句会很痛苦.哦,速度很重要.

The question is if there is a more generic way to test if some node in the reference tree is nil? I need to get a lot of different items and it will be a pain to write all these if statements. Oh and speed is of concern.

推荐答案

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

One elegant way (in my opinion) of handling it is to add getters to structs that are used as pointers. This "technique" is also used by the generated Go code of protobuf, and it allows natural chaining of method calls without having to worry about runtime panic due to nil pointers.

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

In your example the Bar and Baz structs are used as pointers, so arm them with getters. The focus is on adding methods with pointer receiver, and first it must be checked if the receiver is nil. If so, return the zero value of the result type. If not, proceed to return the field of the struct:

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 作为指针参数传递永远不会出错).

The good thing about methods with pointer receivers is that you may call them with nil receivers. It does not cause a runtime panic until you try to refer to their fields, which we don't, that's why we first check if the receiver is nil (ultimately, receivers act as normal parameters–and it's never an error to pass nil as a pointer argument).

有了上面的 getter,使用就简化为这样,并且在任何这些示例中都不会发生运行时恐慌:

Having the above getters, use is simplified to this, and no runtime panic occurs in any of these examples:

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

Go Playground 上试试.

这篇关于测试嵌套结构中的 nil 值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆