### 2.4.1. 元組賦值

元組賦值是另一種形式的賦值語句，它允許同時更新多個變量的值。在賦值之前，賦值語句右邊的所有表達式將會先進行求值，然後再統一更新左邊對應變量的值。這對於處理有些同時出現在元組賦值語句左右兩邊的變量很有幫助，例如我們可以這樣交換兩個變量的值：

```Go
x, y = y, x

a[i], a[j] = a[j], a[i]
```

或者是計算兩個整數值的的最大公約數（GCD）（譯註：GCD不是那個敏感字，而是greatest common divisor的縮寫，歐幾里德的GCD是最早的非平凡算法）：

```Go
func gcd(x, y int) int {
	for y != 0 {
		x, y = y, x%y
	}
	return x
}
```

或者是計算斐波納契數列（Fibonacci）的第N個數：

```Go
func fib(n int) int {
	x, y := 0, 1
	for i := 0; i < n; i++ {
		x, y = y, x+y
	}
	return x
}
```

元組賦值也可以使一繫列瑣碎賦值更加緊湊（譯註: 特别是在for循環的初始化部分），

```Go
i, j, k = 2, 3, 5
```

但如果表達式太複雜的話，應該盡量避免過度使用元組賦值；因爲每個變量單獨賦值語句的寫法可讀性會更好。

有些表達式會産生多個值，比如調用一個有多個返迴值的函數。當這樣一個函數調用出現在元組賦值右邊的表達式中時（譯註：右邊不能再有其它表達式），左邊變量的數目必鬚和右邊一致。

```Go
f, err = os.Open("foo.txt") // function call returns two values
```

通常，這類函數會用額外的返迴值來表達某種錯誤類型，例如os.Open是用額外的返迴值返迴一個error類型的錯誤，還有一些是用來返迴布爾值，通常被稱爲ok。在稍後我們將看到的三個操作都是類似的用法。如果map査找（§4.3）、類型斷言（§7.10）或通道接收（§8.4.2）出現在賦值語句的右邊，它們都可能會産生兩個結果，有一個額外的布爾結果表示操作是否成功：

```Go
v, ok = m[key]             // map lookup
v, ok = x.(T)              // type assertion
v, ok = <-ch               // channel receive
```

譯註：map査找（§4.3）、類型斷言（§7.10）或通道接收（§8.4.2）出現在賦值語句的右邊時，併不一定是産生兩個結果，也可能隻産生一個結果。對於值産生一個結果的情形，map査找失敗時會返迴零值，類型斷言失敗時會發送運行時panic異常，通道接收失敗時會返迴零值（阻塞不算是失敗）。例如下面的例子：

```Go
v = m[key]                // map査找，失敗時返迴零值
v = x.(T)                 // type斷言，失敗時panic異常
v = <-ch                  // 管道接收，失敗時返迴零值（阻塞不算是失敗）

_, ok = m[key]            // map返迴2個值
_, ok = mm[""], false     // map返迴1個值
_ = mm[""]                // map返迴1個值
```

和變量聲明一樣，我們可以用下劃線空白標識符`_`來丟棄不需要的值。

```Go
_, err = io.Copy(dst, src) // 丟棄字節數
_, ok = x.(T)              // 隻檢測類型，忽略具體值
```

