2015-12-09 07:45:11 +00:00
|
|
|
|
### 2.4.1. 元組賦值
|
|
|
|
|
|
2015-12-26 12:05:30 +00:00
|
|
|
|
元組賦值是另一種形式的賦值語句,它允許同時更新多個變量的值。在賦值之前,賦值語句右邊的所有表達式將會先進行求值,然後再統一更新左邊對應變量的值。這對於處理有些同時出現在元組賦值語句左右兩邊的變量很有幫助,例如我們可以這樣交換兩個變量的值:
|
2015-12-09 07:45:11 +00:00
|
|
|
|
|
|
|
|
|
```Go
|
|
|
|
|
x, y = y, x
|
|
|
|
|
|
|
|
|
|
a[i], a[j] = a[j], a[i]
|
|
|
|
|
```
|
|
|
|
|
|
2015-12-26 08:57:06 +00:00
|
|
|
|
或者是計算兩個整數值的的最大公約數(GCD)(譯註:GCD不是那個敏感字,而是greatest common divisor的縮寫,歐幾里德的GCD是最早的非平凡算法):
|
2015-12-09 07:45:11 +00:00
|
|
|
|
|
|
|
|
|
```Go
|
|
|
|
|
func gcd(x, y int) int {
|
|
|
|
|
for y != 0 {
|
|
|
|
|
x, y = y, x%y
|
|
|
|
|
}
|
|
|
|
|
return x
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2015-12-26 08:57:06 +00:00
|
|
|
|
或者是計算斐波納契數列(Fibonacci)的第N個數:
|
2015-12-09 07:45:11 +00:00
|
|
|
|
|
|
|
|
|
```Go
|
|
|
|
|
func fib(n int) int {
|
|
|
|
|
x, y := 0, 1
|
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
|
x, y = y, x+y
|
|
|
|
|
}
|
|
|
|
|
return x
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2015-12-26 08:57:06 +00:00
|
|
|
|
元組賦值也可以使一繫列瑣碎賦值更加緊湊(譯註: 特别是在for循環的初始化部分),
|
2015-12-09 07:45:11 +00:00
|
|
|
|
|
|
|
|
|
```Go
|
|
|
|
|
i, j, k = 2, 3, 5
|
|
|
|
|
```
|
|
|
|
|
|
2015-12-26 08:57:06 +00:00
|
|
|
|
但如果表達式太複雜的話,應該盡量避免過度使用元組賦值;因爲每個變量單獨賦值語句的寫法可讀性會更好。
|
2015-12-09 07:45:11 +00:00
|
|
|
|
|
2015-12-26 12:05:30 +00:00
|
|
|
|
有些表達式會産生多個值,比如調用一個有多個返迴值的函數。當這樣一個函數調用出現在元組賦值右邊的表達式中時(譯註:右邊不能再有其它表達式),左邊變量的數目必鬚和右邊一致。
|
2015-12-09 07:45:11 +00:00
|
|
|
|
|
|
|
|
|
```Go
|
|
|
|
|
f, err = os.Open("foo.txt") // function call returns two values
|
|
|
|
|
```
|
|
|
|
|
|
2015-12-26 12:05:30 +00:00
|
|
|
|
通常,這類函數會用額外的返迴值來表達某種錯誤類型,例如os.Open是用額外的返迴值返迴一個error類型的錯誤,還有一些是用來返迴布爾值,通常被稱爲ok。在稍後我們將看到的三個操作都是類似的用法。如果map査找(§4.3)、類型斷言(§7.10)或通道接收(§8.4.2)出現在賦值語句的右邊,它們都可能會産生兩個結果,有一個額外的布爾結果表示操作是否成功:
|
2015-12-09 07:45:11 +00:00
|
|
|
|
|
|
|
|
|
```Go
|
|
|
|
|
v, ok = m[key] // map lookup
|
|
|
|
|
v, ok = x.(T) // type assertion
|
|
|
|
|
v, ok = <-ch // channel receive
|
|
|
|
|
```
|
|
|
|
|
|
2015-12-26 12:05:30 +00:00
|
|
|
|
譯註:map査找(§4.3)、類型斷言(§7.10)或通道接收(§8.4.2)出現在賦值語句的右邊時,併不一定是産生兩個結果,也可能隻産生一個結果。對於值産生一個結果的情形,map査找失敗時會返迴零值,類型斷言失敗時會發送運行時panic異常,通道接收失敗時會返迴零值(阻塞不算是失敗)。例如下面的例子:
|
2015-12-26 08:57:06 +00:00
|
|
|
|
|
|
|
|
|
```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個值
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
和變量聲明一樣,我們可以用下劃線空白標識符`_`來丟棄不需要的值。
|
2015-12-09 07:45:11 +00:00
|
|
|
|
|
|
|
|
|
```Go
|
|
|
|
|
_, err = io.Copy(dst, src) // 丟棄字節數
|
2015-12-26 08:57:06 +00:00
|
|
|
|
_, ok = x.(T) // 隻檢測類型,忽略具體值
|
2015-12-09 07:45:11 +00:00
|
|
|
|
```
|
|
|
|
|
|