Is there any way to handle nil pointer in Golang without using if/else?

huangapple go评论82阅读模式
英文:

Is there any way to handle nil pointer in Golang without using if/else?

问题

我有一个示例代码:

type MyStruct struct {    
    ...
    MyField *MyOtherStruct
    ...
}

type MyOtherStruct struct {
    ...
    MyOtherField *string
    ...
}

// 我有一个接收 MyOtherField 作为参数的函数
func MyFunc(myOtherField *string) {
    ...
}

// 如何避免在这里使用 if/else
if MyStruct.MyField != nil {
    MyFunc((*MyStruct.MyField).MyOtherField)
} else {
    MyFunc(nil)
}

在我的示例中,我必须使用 if/else 来处理 MyStruct.MyField 是否为 nil。我想找到一种缩短代码的方法。

我想找到一种类似于 JavaScript 中的 MyFunc(MyStruct.MyField ? (*MyStruct.MyField).MyOtherField : nil) 的方式。

英文:

I have this piece of code for example:

type MyStruct struct {    
    ...
    MyField *MyOtherStruct
    ...
}

type MyOtherStruct struct {
    ...
    MyOtherField *string
    ...
}

// I have a fuction that receive MyOtherField as parameter
func MyFunc(myOtherField *string) {
    ...
}

// How can I avoid using if/else here
if MyStruct.MyField != nil {
    MyFunc((*MyStruct.MyField).MyOtherField)
} else {
    MyFunc(nil)
}

In my example, I have to use if else to handle whether MyStruct.MyField is nil or not. I would like to find a way to shorten my code.

I would like to find some way like MyFunc(MyStruct.MyField ? (*MyStruct.MyField).MyOtherField : nil) in JavaScript.

答案1

得分: 5

不,你不能像在JS中那样做。这只是一种语法糖。但是,有一些替代方案。

首先,你可以简单地写成:

if MyStruct.MyField != nil {
    MyFunc(MyStruct.MyField.MyOtherField)
} else {
    MyFunc(nil)
}

在某些情况下,编写使用指针接收器的getter函数可能是有意义的:

func (m *MyOtherStruct) GetOtherField() *OtherFieldType {
   if m==nil {
      return nil
   }
   return m.OtherField
}

然后你可以这样做:

MyFunc(MyStruct.MyField.GetOtherField())

这就是gRPC生成Go模型的方式。尽管如此,通常不建议这样做,因为它会隐藏一些微妙的错误。最好是明确地检查你在使用它的地方。

英文:

No, you cannot do what you used to do in JS. It is just syntactic sugar. But, there are some alternatives.

First, you can simply write:

if MyStruct.MyField != nil {
    MyFunc(MyStruct.MyField.MyOtherField)
} else {
    MyFunc(nil)
}

In some cases it may make sense to write getters that work with pointer receivers:

func (m *MyOtherStruct) GetOtherField() *OtherFieldType {
   if m==nil {
      return nil
   }
   return m.OtherField
}

Then you can do:

MyFunc(MyStruct.MyField.GetOtherField())

This is how gRPC generates Go models. It is not usually advisable, though. It hides subtle bugs. It is best to be explicit and check where you use it.

答案2

得分: 3

GoLang没有'coalescing nil'运算符或三元条件(至少目前如此),但如果你想从主流程中删除else,你可以将其提取到一个辅助函数中。

我将其示例化为一个带有*MyStruct接收器的函数,但它也可以作为一个独立的函数接受*MyStruct参数存在:

func (ms *MyStruct) getMyOtherFieldOrNil() *string {
   if ms.MyField == nil {
      return nil
   }
   return ms.MyField.MyOtherField
}

函数的名称清楚地表明了nil结果是合法的,以避免任何潜在的混淆。

然后,当你需要MyField.MyOtherFieldnil(当MyFieldnil时),你可以使用这个函数代替if {} else {}结构:

    ms := &MyStruct{}

    // ...

    MyFunc(ms.getMyOtherFieldOrNil())

脚注

这与Burak的答案类似,但避免了我认为与"subtle bugs"有关的nil receivers的潜在问题。这个稍微高级的辅助函数只会在一个nil的*MyStruct接收器上调用时引发panic(正如它应该做的),但在其他情况下实现了相同的目的。

英文:

GoLang has no 'coalescing nil' operator or ternary conditions (by design, currently at least) but if you want to remove the else from your main flow you can extract it into a helper func.

I've illustrated this as a func with a *MyStruct receiver but it could equally exist as a standalone fun accepting a *MyStruct arg:

func (ms *MyStruct) getMyOtherFieldOrNil() *string {
   if ms.MyField == nil {
      return nil
   }
   return ms.MyField.MyOtherField
}

The name of the func makes it clear that a nil result is legitimate, to avoid any potential for confusion.

Then, when you need the MyField.MyOtherField or nil (when MyField is nil) you can use this in place of the if {} else {} construct:

    ms := &MyStruct{}

    // ...

    MyFunc(ms.getMyOtherFieldOrNil())

Footnote

This is similar to Burak's answer but avoids the potential pitfalls of nil receivers which I believe are responsible for the "subtle bugs" mentioned. This slightly higher level helper func will simply panic if called on a nil *MyStruct receiver (as it should), but otherwise achieves much the same purpose.

答案3

得分: 1

你无法避免使用 if else。即使你为 MyStruct 定义了一个 getter,其中仍然包含 if else。所以我建议你保留原始代码以保持清晰。

英文:

You cannot avoid using if else. Even through you define a getter for MyStruct, there still if else inside. So I suggest that you should keep your original code for clear.

答案4

得分: -1

func TernaryFunc(statement bool, a, b interface{}) interface{} {
if statement {
return a
}
return b
}

MyFunc(TernaryFunc(MyStruct.MyField == nil, (*MyStruct.MyField).MyOtherField, nil).(string))

我不确定,但可以尝试像这样的一些方法。

英文:
func TernaryFunc(statement bool, a, b interface{}) interface{} {
    if statement {
        return a
    }
    return b
}

MyFunc(TernaryFunc(MyStruct.MyField == nil, (*MyStruct.MyField).MyOtherField, nil).(string))

I'm not sure but try some things like this.

huangapple
  • 本文由 发表于 2022年12月15日 11:11:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/74806443.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定