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

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

问题描述

我在go中有一个深层嵌套的结构.这些是由json解组器构造的.

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

但是,该结构中的某些字段都是'omitifempty'的,因此我以一个可以在各个位置带有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")
    }
}

问题是是否存在一种更通用的方法来测试参考树中的某个节点是否为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.

推荐答案

一种处理它的优雅方法(我认为)是将getters添加到用作指针的结构中. 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结构用作指针,因此使用吸气剂武装它们.重点是使用指针接收器添加方法,首先必须检查接收器是否为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).

具有上述吸气剂,将其简化使用,并且在以下任何示例中都不会发生运行时恐慌:

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

游乐场上尝试.

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

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