使用“comma ok”习语还是返回指针?

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

Use 'comma ok' idiom or return pointer?

问题

考虑以下Go代码片段:

func sheep() (int, bool) {
    return 1, true
}

func main() {
    if dolly, ok := sheep(); ok {
         //做一些事情
    }
}

根据我在《Effective Go》(http://golang.org/doc/effective_go.html)中的阅读,这被称为“逗号ok”习语。据我所知,这是用来区分“找到”和“未找到”两种情况的。

同样的效果可以通过以下方式实现:

type Sheep struct {}

func sheep() *Sheep {
    return &Sheep{}
}

func main() {
    if dolly := sheep(); dolly != nil {
         //做一些事情
    }
}

后一种示例似乎达到了相同的目的,甚至更好。在“逗号ok”示例中,赋值只在if块中有效。

也许我忽略了一些考虑因素。哪种模式更受推荐?为什么?

一个简短的示例:http://play.golang.org/p/ATxvle38iE

英文:

Consider the following Go snippet:

func sheep() (int, bool) {
    return 1, true
}

func main() {
    if dolly, ok := sheep() {
         //do something
    }
}

As I read on 'Effective Go' this is called the 'comma ok' idiom. As far as I can tell this is used to distinguish from a 'found' and 'not found' thing.

The same can be achieved via:

type Sheep struct {}

func sheep() *Sheep {
    return &Sheep{}
}

func main() {
    if dolly := sheep(); dolly != nil {
         //do something
    }
}

The latter example seems to fulfill the same purpose, perhaps even nicer. With the 'comma ok' example the assignment is only valid in the if block.

Perhaps I'm missing some considerations. Which pattern is preferred? And why?

A brief example: http://play.golang.org/p/ATxvle38iE

答案1

得分: 14

在Go语言中,nil值可能是一个完全有效的值。例如,一个nil切片(几乎)可以像一个空切片一样使用,对于用户定义的指针接收器也可能是如此。

因此,逗号-OK或逗号-错误惯用法通常更受青睐,因为它明确告诉函数的调用者需要显式处理错误情况(或非OK情况)。

所以,当Sheep返回值可能无效时,以下是惯用的写法:

func sheep() (*Sheep, bool) {...}
func sheep() (s *Sheep, ok bool) {...}  // 添加名称以使其更清晰
func sheep() (*Sheep, error) {...}

而当返回值始终有效时,以下是惯用的写法:

func sheep() *Sheep {...}

这是Go与其他语言不同的地方,其他语言中可能使用nil返回值来表示错误。逗号-OK和逗号-错误的惯用法巧妙地避免了使用nil指针的“十亿美元错误”,使得不处理无效返回值的代码看起来是错误的。如果你编写惯用的代码,你可以立即看到错误被忽略的地方:例如,这里对s2的赋值立即引起怀疑:

s1 := sheep()
s2, _ := sheep()
英文:

In Go, a nil value may be a perfectly good value. For example a nil slice works (almost) like an empty slice, and the same may be true for user-defined pointer receivers.

For this reason, the comma-ok or comma-error idiom is usually preferred because it makes it obvious that the caller of the function needs to treat the error case (or the not-ok) case explicitly.

So, these are idiomatic when the Sheep return value may not be valid:

func sheep() (*Sheep, bool) {...}
func sheep() (s *Sheep, ok bool) {...}  // Adding names to make it clearer
func sheep() (*Sheep, error) {...}

And this is idiomatic only when the return value is always valid:

func sheep() *Sheep {...}

This is an area where Go is different from other languages, where a nil return value may be used to signal an error. The Go idioms of comma-ok and comma-error neatly work around the "billion-dollar mistake" of nil pointers by making code that doesn't deal with invalid return values look wrong. If you write idiomatic code, you can immediately see when errors are being ignored: for example the assignment to s2 here immediately jumps out as suspicious:

s1 := sheep()
s2, _ := sheep()

答案2

得分: 7

两种方式都可以接受,而且你还漏掉了最常见的习惯用法;返回 value, error

在《Effective Go》中提到的“逗号-OK”习惯用法通常用于内置操作,比如从映射或通道中读取,以及类型断言。

如果需要返回一个不需要指针的值,或者指针不方便,或者 nil 是一个有效的值,我会使用它;但根据情况,value, error 也可以同样好用。

英文:

Both are acceptable, plus you missed the most common idiom; Returning value, error.

The "comma ok" idiom as referenced in "Effective Go" is typically reserved for the builtin operations, like reading from a map or channel, and for type assertions.

I would use it if you need to return a value where a pointer would be unnecessary, inconvenient, or where nil is a valid value; but depending on the situation value, error could be just as good.

huangapple
  • 本文由 发表于 2014年4月29日 00:43:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/23346636.html
匿名

发表评论

匿名网友

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

确定