這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
使用指派陳述式可以更新一個變數的值,最簡單的指派陳述式是將要被賦值的變數放在=的左邊,新值的運算式放在=的右邊。
x = 1 // 命名變數的賦值*p = true // 通過指標間接賦值person.name = "bob" // 結構體欄位賦值count[x] = count[x] * scale // 數組、slice或map的元素賦值
特定的二元算術運算子和指派陳述式的複合操作有一個簡潔形式,例如上面最後的語句可以重寫為:
count[x] *= scale
這樣可以省去對Variant 運算式的重複計算。
數值變數也可以支援++
遞增和--
遞減語句(譯註:自增和自減是語句,而不是運算式,因此x = i++
之類的運算式是錯誤的):
v := 1 v++ // 等價方式 v = v + 1;v 變成 2v-- // 等價方式 v = v - 1;v 變成 1
元組賦值
元組賦值是另一種形式的指派陳述式,它允許同時更新多個變數的值。在賦值之前,指派陳述式右邊的所有運算式將會先進行求值,然後再統一更新左邊對應變數的值。這對於處理有些同時出現在元組指派陳述式左右兩邊的變數很有協助,例如我們可以這樣交換兩個變數的值:
x, y = y, x a[i], a[j] = a[j], a[i]
例子求最大公約數:
//計算兩個整數的最大公約數func gcd(x, y int) int { for y != 0 { x, y = y, x%y } return x }
例子費伯納西數列(Fibonacci):
//計算費伯納西數列(Fibonacci)的第N個數func fib(n int) int { x, y := 0, 1 for i := 0; i < n; i++ { x, y = y, x+y } return x }
元組賦值也可以使一系列瑣碎賦值更加緊湊:
i, j, k = 2, 3, 5
但如果運算式太複雜的話,應該盡量避免過度使用元組賦值;因為每個變數單獨指派陳述式的寫法可讀性會更好。
有些運算式會產生多個值,比如調用一個有多個傳回值的函數。當這樣一個函數調用出現在元組賦值右邊的運算式中時,左邊變數的數目必須和右邊一致。
f, err = os.Open("foo.txt") // function call returns two values
通常,這類函數會用額外的傳回值來表達某種錯誤類型,例如os.Open是用額外的傳回值返回一個error類型的錯誤,還有一些是用來返回布爾值,通常被稱為ok。在稍後我們將看到的三個操作都是類似的用法。如果map尋找、類型斷言或通道接收出現在指派陳述式的右邊,它們都可能會產生兩個結果,有一個額外的布爾結果表示操作是否成功:
v, ok = m[key] // map lookupv, ok = x.(T) // type assertionv, ok = <-ch // channel receive
註:map尋找、類型斷言或通道接收出現在指派陳述式的右邊時,並不一定是產生兩個結果,也可能只產生一個結果。對於值產生一個結果的情形,map尋找失敗時會返回零值,類型宣告失敗時會發送運行時panic異常,通道接收失敗時會返回零值(阻塞不算是失敗)。例如下面的例子:
v = m[key] // map尋找,失敗時返回零值v = x.(T) // type斷言,失敗時panic異常v = <-ch // 管道接收,失敗時返回零值(阻塞不算是失敗) _, ok = m[key] // map返回2個值_, ok = mm[""], false // map返回1個值_ = mm[""] // map返回1個值
和變數聲明一樣,我們可以用底線空白標識符_
來丟棄不需要的值。
_, err = io.Copy(dst, src) // 丟棄位元組數_, ok = x.(T) // 只檢測類型,忽略具體值
可賦值性
指派陳述式是顯式的賦值形式,但是程式中還有很多地方會發生隱式的賦值行為:函數調用會隱式地將調用參數的值賦值給函數的參數變數,一個返回語句將隱式地將返回操作的值賦值給結果變數,一個複合類型的字面量也會產生賦值行為。例如下面的語句:
medals := []string{"gold", "silver", "bronze"}
隱式地對slice的每個元素進行賦值操作,類似這樣寫的行為:
medals[0] = "gold" medals[1] = "silver" medals[2] = "bronze"
map和chan的元素,雖然不是普通的變數,但是也有類似的隱式賦值行為。
不管是隱式還是顯式地賦值,在指派陳述式左邊的變數和右邊最終的求到的值必須有相同的資料類型。更直白地說,只有右邊的值對於左邊的變數是可賦值的,指派陳述式才是允許的。
可賦值性的規則對於不同類型有著不同要求,對每個新類型特殊的地方我們會專門解釋。對於目前我們已經討論過的類型,它的規則是簡單的:類型必須完全符合,nil可以賦值給任何指標或參考型別的變數。常量則有更靈活的賦值規則,因為這樣可以避免不必要的顯式的類型轉換。
對於兩個值是否可以用==
或!=
進行相等比較的能力也和可賦值能力有關係:對於任何類型的值的相等比較,第二個值必須是對第一個實值型別對應的變數是可賦值的,反之依然。