Test for nil values in nested stucts

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.

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
}

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

Try it on the Go Playground.

Leave a Comment