How to understand the golang multi-return value

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

How to understand the golang multi-return value

问题

Golang支持将多个返回值分配给多个左侧变量。例如:

func test() (string, string) {
  return "1", "1"
}

a, b := test()

或者

a, _ := test()

接收变量的数量和返回值必须匹配:

b = test()   // 错误

但是对于一些内置类型,例如[]<-,支持变量数量不定的返回值:

key, exist := map[key]

key := map[key]

我可以像这样从通道中读取值:

c <- myChan

c, exist <- myChan

我们如何解释这种不一致性?这是Go核心运行时/语言保留的功能吗?

英文:

Golang supports assigning multiple return values to multiple left hand side variables. E.g:

func test() (string, string) {
  return &quot;1&quot;, &quot;1&quot;
}

a, b := test()

or

a, _ := test()

and the number of receiving variables and return values must match:

b = test()   //wrong

But for some built-in types, such as [] or <-, a variable number of return values are supported

key, exist := map[key]

key := map[key]

I can read value from channel like this

c &lt;- myChan

c, exist &lt;- myChan

How can we explain the inconsistency? Is this a capability reserved to the core go runtime/language?

答案1

得分: 12

这种行为在golang规范中明确指定:

  1. 接收操作符

在赋值或初始化的特殊形式中使用的接收表达式

x, ok = <-ch
x, ok := <-ch
var x, ok = <-ch
var x, ok T = <-ch

会产生一个额外的无类型布尔结果,报告通信是否成功。如果接收到的值是通过成功的发送操作传递到通道的,则ok的值为true;如果通道已关闭且为空,则ok的值为false。

  1. 索引表达式

在赋值或初始化的特殊形式中使用的类型为map[K]V的映射a的索引表达式

v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
var v, ok T = a[x]

会产生一个额外的无类型布尔值。如果键x在映射中存在,则ok的值为true;否则为false。

  1. 赋值操作

元组赋值将多值操作的各个元素分配给变量列表。有两种形式。在第一种形式中,右操作数是一个多值表达式,例如函数调用、通道或映射操作或类型断言。左操作数的数量必须与值的数量相匹配。例如,如果f是一个返回两个值的函数:

x, y = f()

将第一个值分配给x,第二个值分配给y。在第二种形式中,左操作数的数量必须等于右边表达式的数量,每个表达式必须是单值的,第n个表达式将分配给左边的第n个操作数。

因此,正如你所看到的,这种行为是由语言设计指定的,你无法自己实现接收操作符索引表达式的这些规定。

英文:

This behavior clearly specified in the golang specification:

  1. Receive operator

>A receive expression used in an assignment or initialization of the special form

x, ok = &lt;-ch
x, ok := &lt;-ch
var x, ok = &lt;-ch
var x, ok T = &lt;-ch

>yields an additional untyped boolean result reporting whether the communication succeeded. The value of ok is true if the value received was delivered by a successful send operation to the channel, or false if it is a zero value generated because the channel is closed and empty.

  1. Index expression

> An index expression on a map a of type map[K]V used in an assignment or initialization of the special form

v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
var v, ok T = a[x]

>yields an additional untyped boolean value. The value of ok is true if the key x is present in the map, and false otherwise.

  1. Assignments

> A tuple assignment assigns the individual elements of a multi-valued operation to a list of variables. There are two forms. In the first, the right hand operand is a single multi-valued expression such as a function call, a channel or map operation, or a type assertion. The number of operands on the left hand side must match the number of values. For instance, if f is a function returning two values,

x, y = f()

>assigns the first value to x and the second to y. In the second form, the number of operands on the left must equal the number of expressions on the right, each of which must be single-valued, and the nth expression on the right is assigned to the nth operand on the left.

Therefore as you can see this behavior being specified by language design and you cannot achieve those specified for Receive operator and Index expression by yourself.

答案2

得分: 2

你正在混淆从函数返回的多个值与所谓的“逗号-ok”习惯用法。

对于函数的返回值,你必须要么处理所有返回值,要么不处理任何返回值。很简单。

“逗号-ok”更加微妙。如果你指定了第二个值,通常会改变行为。考虑以下语句:

v, ok := x.(int)
// 与
v := x.(int)

如果x是一个持有整数的接口,那么一切都很好。然而,如果x持有不同类型的值,第一条语句将正常工作(返回0, false),而第二条语句将引发恐慌。

每种带有“逗号-ok”形式的语句都是不同的特殊情况,它们与其他类型的多重赋值(例如多个函数返回值)不同。你不能将它们进行比较,每种情况都有自己的规则。

英文:

You are confusing multiple values returned from a function with the so-called "comma ok" idiom.

With a function's return values you must either handle all of them, or none of them. Simple.

"Comma ok" is more subtle. Often the behavior is changed if you have a second value specified. Consider these statements:

v, ok := x.(int)
// vs
v := x.(int)

If x is an interface holding an integer, all is well, however, if x holds a different type the first statement will work (returning 0, false), and the second one will panic.

Each type of statement with a "comma ok" form is a different special case, and they are not the same as other kinds of multiple assignments (such as multiple function return values). You cannot compare them, each is its own thing, with its own rules.

huangapple
  • 本文由 发表于 2017年9月18日 12:28:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/46271620.html
匿名

发表评论

匿名网友

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

确定