doushan7997 2018-01-28 06:50
浏览 56
已采纳

如何检查嵌套指针中的值

How can I check nested pointer easily?

type inner1 struct {
    value string
}

type inner2 struct {
    value *inner1
}

type outter struct {
    value *inner2
}

I have data like this:

o := &outter{
    value: &inner2{
        value: &inner1{
            value: "I need this data",
        },
    },
} 

If I want to get data from this, I need to check for nil pointer.

func printValue(o *outter) (string, bool) {
    if o.value != nil {
        v1 := o.value
        if v1.value != nil {
            v2 := v1.value
            return v2.value, true
        }
    }
    return "", false
}

Yea, I can do this. But in my real scenario, this nested pointer part is much longer. I will prefer another way.

I have checked this answer, Test for nil values in golang nested stucts. But I need alternative.

How can I accomplish this. Any efficient and better option?

  • 写回答

3条回答 默认 最新

  • duanquyong8164 2018-01-28 07:12
    关注

    Panic and recover is for exceptional cases. Checking if a pointer is nil is usually not, so you should stay away from it. Checking if a pointer is nil using an if statement is much cleaner than to introduce a deferred function with recover(). Especially as this recover() will stop all other kinds of panic, even those that would result from other reasons than trying to dereference a nil pointer. (Using defer and recover() is also slower than a simple nil check using if.)

    If the data is always required to be a non-nil value, you should consider not using a pointer for it. And if the data is always required to be non-nil but for some reason you are required to use a pointer, then this may be a valid case to let your code panic if any of the pointers are still nil.

    If it may be nil, then you have to check the nil case and handle it appropriately. You have to be explicit about this, Go doesn't help you omit this check.

    To avoid having to check nil in every place, a utility function or method is reasonable. Note that methods can be called even if the receiver is nil which may be useful in such cases.

    For example you may attach the following methods:

    func (i *inner1) Get() (string, bool) {
        if i == nil {
            return "", false
        }
        return i.value, true
    }
    
    func (i *inner2) Get() (string, bool) {
        if i == nil {
            return "", false
        }
        return i.value.Get()
    }
    
    func (o *outter) Get() (string, bool) {
        if o == nil {
            return "", false
        }
        return o.value.Get()
    }
    

    Note that each Get() method requires to check a single pointer, doesn't matter how complex the data structure is.

    Testing it:

    o := &outter{
        value: &inner2{
            value: &inner1{
                value: "I need this data",
            },
        },
    }
    fmt.Println(o.Get())
    
    o.value.value = nil
    fmt.Println(o.Get())
    
    o.value = nil
    fmt.Println(o.Get())
    
    o = nil
    fmt.Println(o.Get())
    

    Output (try it on the Go Playground):

    I need this data true
     false
     false
     false
    

    The above solution hides the internals of outter which is useful for those using outter (doesn't need updating the clients if internals of outter change, just the outter.Get() method).

    A similar approach would be to add methods that only return the field of the receiver struct:

    func (i *inner1) Value() (string, bool) {
        if i == nil {
            return "", false
        }
        return i.value, true
    }
    
    func (i *inner2) Inner1() *inner1 {
        if i == nil {
            return nil
        }
        return i.value
    }
    
    func (o *outter) Inner2() *inner2 {
        if o == nil {
            return nil
        }
        return o.value
    }
    

    This approach requires clients to know internals of outter, but similarly it does not require any nil checks when using it:

    o := &outter{
        value: &inner2{
            value: &inner1{
                value: "I need this data",
            },
        },
    }
    fmt.Println(o.Inner2().Inner1().Value())
    
    o.value.value = nil
    fmt.Println(o.Inner2().Inner1().Value())
    
    o.value = nil
    fmt.Println(o.Inner2().Inner1().Value())
    
    o = nil
    fmt.Println(o.Inner2().Inner1().Value())
    

    Output is the same. Try this one on the Go Playground.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥20 基于MSP430f5529的MPU6050驱动,求出欧拉角
  • ¥20 Java-Oj-桌布的计算
  • ¥15 powerbuilder中的datawindow数据整合到新的DataWindow
  • ¥20 有人知道这种图怎么画吗?
  • ¥15 pyqt6如何引用qrc文件加载里面的的资源
  • ¥15 安卓JNI项目使用lua上的问题
  • ¥20 RL+GNN解决人员排班问题时梯度消失
  • ¥60 要数控稳压电源测试数据
  • ¥15 能帮我写下这个编程吗
  • ¥15 ikuai客户端l2tp协议链接报终止15信号和无法将p.p.p6转换为我的l2tp线路