Go 中哪些语义规则决定何时发生单值赋值与何时发生双值赋值?

Lon*_*ner -1 syntax dictionary go assignment-operator semantics

在研究map围棋之旅:不同诱变地图,有一件事我发现令人意外的是,我们可以使用任一值分配或两个值分配访问值的关键在一个地图。示例代码:

package main

import (
    "fmt"
)

func main() {
    m := map[int]int{2: 4, 3: 9, 4: 16}
    
    // Example 1
    fmt.Println(m[2])
    
    // Example 2
    v := m[2]
    fmt.Println(v)
    
    // Example 3
    v, ok := m[2]
    fmt.Println(v, ok)
}
Run Code Online (Sandbox Code Playgroud)

输出:

4
4
4 true
Run Code Online (Sandbox Code Playgroud)

使用相同的语法支持一值和二值赋值涉及哪些语义规则?Go 中是否还有其他这样的特殊形式,根据赋值运算符的左侧,以相同的语法支持一值和二值赋值?

此外,我可以自己编写一个函数foo(),根据赋值运算符的左侧返回一个值或两个值吗?

Mar*_*arc 6

映射索引操作的一或二值分配是一种特殊形式,为方便起见,不幸的是不能在“正常”分配中完成。

正常赋值表达式:

该规范对元组分配有以下说明:

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

x, y = f()

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

one, two, three = '?', '?', '?'

这对于赋值中的值的数量没有任何含糊的余地。

一或二值表达式:

有 4 种情况,表达式的左侧允许一个和两个值。其中三个是赋值表达式的特殊形式,最后一个是range子句。

索引表达式

索引表达式的形式定义为a[x],地图除外:

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

v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
Run Code Online (Sandbox Code Playgroud)

产生一个额外的无类型布尔值。

接收操作符

Receive Operator也会发生同样的情况,通常采用以下形式x <-ch

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

x, ok = <-ch
x, ok := <-ch
var x, ok = <-ch
var x, ok T = <-ch
Run Code Online (Sandbox Code Playgroud)

产生一个额外的无类型布尔结果报告通信是否成功。

类型断言

一旦更多的提到特殊形式类型断言,一般形式x.(T)

特殊形式的赋值或初始化中使用的类型断言

v, ok = x.(T)
v, ok := x.(T)
var v, ok = x.(T)
var v, ok T1 = x.(T)
Run Code Online (Sandbox Code Playgroud)

产生一个额外的无类型布尔值。

范围条款

带有 range 子句for 语句具有与其相关联的宽松语言,因为它不是对正常赋值表达式的修改:

左侧的函数调用每次迭代评估一次。对于每次迭代,如果存在相应的迭代变量,则会按如下方式生成迭代值:

Range expression                          1st value          2nd value

array or slice  a  [n]E, *[n]E, or []E    index    i  int    a[i]       E
string          s  string type            index    i  int    see below  rune
map             m  map[K]V                key      k  K      m[k]       V
channel         c  chan E, <-chan E       element  e  E
Run Code Online (Sandbox Code Playgroud)

用于非赋值:

如上所述,所有三种特殊表格仅用于分配。尝试在其他表达式(函数调用、返回等...)中使用多值返回将失败,因为这些不是赋值并且不会从特殊形式 中受益。