同其它语言一样,go 的赋值运算符也是 ​​=​​​,不过 go 的 ​​=​​ 更加强大,它支持元组赋值(Tuple Assignment),有人称其为平行赋值

同样在 go 里,要求 ​​=​​ 左侧的变量类型和右侧值的类型匹配,否则会编译不通过。

1. 赋值

举几个例子:

var x int = 10
var y int = 10

x++ // ok
y = x++ // not ok
x *= 10 // ok, same as x = x * 10
x-- // ok
++x // not ok
--x // not ok

x, y = 30, 40 // ok
x, y = y, x // ok, swap value
  • go 的​​x++​​​ 不是表达式,而是语句(go 应该是想避免不必要的争论,干脆就不支持它吧),因此​​y = x++​​ 这种写法是不正确的。
  • go 不支持​​++x​​​ 和​​--x​​​ 写法。(有一个​​x++​​​,​​x--​​ 就够了,干嘛搞那么多?)

在 c/c++ 语言的论坛或一些群里总看到有人讨论类似 ​​y = x++ + ++x​​​ 的结果是啥,甚至搬出汇编语言来强行解释结果。借用某大佬的一句话:用汇编学 C 就像是根据大便的位置来判断自己屁眼在哪……(有些物理系的同学可能会喷我,抱歉。。。)
在 go 里这种无聊的讨论永远不存在,go 从源头将这种无意义的争论扼杀在了摇篮里。

2. 元组赋值

在 go 中,有些表达式会产生多个值。比如:

x, y, z := 10, 20, 30

有些函数也会返回多个值。比如:

n, err := io.Copy(dst, src)

还有 map 的查找,类型断言,通道接收也会返回多个值(也会返回一个值)。

v, ok = m["name"] // 如果没有查找到 ok 为 false
v, ok = x.(int) // 断言 x 的类型是否为 int,这是类型断言语法
v, ok = <-ch // 如果通道已经关闭,ok 为 false

下面的例子说明了 map 查找可以返回一个值,也可以返回 2 个值:

package main

import "fmt"

func main() {
m := make(map[string]string)
m["name"] = "allen"
m["sex"] = ""

v, ok := m["name"]
fmt.Printf("v = %s, ok = %v\n", v, ok) // v = allen, ok = true

v, ok = m["age"]
fmt.Printf("v = %s, ok = %v\n", v, ok) // v = , ok = false

v, ok = m["sex"]
fmt.Printf("v = %s, ok = %v\n", v, ok) // v = , ok = true

v = m["name"]
fmt.Printf("v = %s\n", v) // v = allen

v = m["age"]
fmt.Printf("v = %s\n", v) // v =

v = m["sex"]
fmt.Printf("v = %s\n", v) // v =

上面的程序输出结果如下:


020-赋值(Assignment)_元组


图1 map 查找输出结果


上面的例子告诉我们,map 查找如果只返回一个值,我们没有办法判断该值是否在 map 中。所以只能使用 map 查找返回的第 2 个值来判断 map 中是否存在该值。一般可以这样使用:

if v, ok := m["name"]; !ok {
fmt.Println("name not existed")
}

3. 总结

  • 掌握 go 的赋值方法
  • 掌握 map 查找如何判断 key 是否存在,类似的还有类型断言,通道接收值