问题描述
在研究A Tour of Go: Mutating Maps中的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)
}
输出:
4
4
4 true
使用相同的语法支持一值和二值赋值涉及哪些语义规则? Go中是否还有其他特殊形式支持相同值的一值和二值分配,具体取决于赋值运算符的左侧?
我还可以自己编写一个函数foo()
,该函数可以根据赋值运算符的左侧返回一个值或两个值吗?
解决方法
地图索引操作的一两个值赋值是一种特殊形式,为方便起见,不幸的是,它不能在“常规”赋值中完成。
常规分配表达式:
该规范对元组assignments的描述如下:
元组分配分配多值的各个元素 操作到变量列表。有两种形式。首先, 右手操作数是单个多值表达式,例如 函数调用,通道或映射操作或类型声明。的 左侧的操作数数目必须与 价值观。例如,如果f是一个返回两个值的函数,
x,y = f()
将第一个值分配给x,将第二个值分配给y。在第二种形式中 左边的操作数必须等于 右边的表达式,每个表达式必须为单值,并且 右边的第n个表达式被分配给 左:
one,two,three = '一','二','三'
这对赋值中的值数量没有歧义。
一个或两个值的表达式:
在4种情况下,表达式的左侧都允许一个和两个值。其中三个是赋值表达式的特殊形式,最后一个是range
子句。
索引表达式:
Index expressions被定义为a[x]
形式,但地图明显例外:
在分配中使用的类型为map [K] V的map a上的索引表达式 或特殊形式
的初始化v,ok = a[x] v,ok := a[x] var v,ok = a[x]
产生另一个无类型的布尔值。
接收运营商:
Receive Operator也会发生同样的情况,通常其格式为x <-ch
:
一个接收表达式,用于赋值或初始化 特殊形式
x,ok = <-ch x,ok := <-ch var x,ok = <-ch var x,ok T = <-ch
产量 附加的无类型布尔结果,报告是否 交流成功。
类型断言:
在type assertions中通常会以x.(T)
的形式提到特殊形式:
在类型的赋值或初始化中使用的类型断言 特殊形式
v,ok = x.(T) v,ok := x.(T) var v,ok = x.(T) var v,ok T1 = x.(T)
产生另一个无类型的布尔值。
范围子句:
for statement with range clause的语言较宽松,因为它不是对常规赋值表达式的修改:
左侧的函数调用每次迭代评估一次。对于每个 迭代,如果各自 存在迭代变量:
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
用于非分配:
如上所述,所有三种特殊形式仅用于分配。尝试在其他表达式(函数调用,返回等)中使用多值返回将失败,因为这些不是赋值,也无法从特殊形式中受益。