變數(Variable)是儲存值的位置,變數宣告可以給予識別名稱(Identifier)、型態與初始值,在 Go 中寫下的 10、3.14、true、"Justin" 等稱之為常數(Constant),常數宣告可給予這些常數識別名稱。
基本變數宣告
要在 Go 中進行變數宣告有多種形式,使用 var 是最基本的方式。例如,宣告一個 x 變數,型態為 int,初始值為 10:
var x int = 10
這麼一來,從 x 這個位置開始,儲存了 int 長度的值 10,在宣告變數時,型態是寫在名稱之後。你也可以同時建立多個變數並指定初值:
var x, y, z int = 10, 20, 30
這樣的話,x、y、z 的型態都是 int,值分別是 10、20、30。如果宣告多個變數時,想要指定不同的型態,可以使用批量宣告:
var (
    x int = 10
    y string = "Justin"
    z bool = true
)
如果宣告變數時指定了型態,但未指定初值,那麼編輯器會提供預設初值,例如:
var (
    a bool        
    b int32
    c float32
    d string
    e complex128
)
在上面的宣告中,a、b、c、d、e 的值分別會是 false、0、0.0、"" 與 0 + 0i。在 Go 中,宣告了變數,程式中卻沒有取用的動作,那麼會發生 declared and not used 的編譯錯誤。
自動推斷型態
在 Go 中宣告變數並指定值時,可以不用提供型態,由編譯器自動推斷型態,例如:
var x = 10
上頭的 x 型態會是 int,而底下的宣告:
var x, y, z = 10, 3.14, "Justin"
x、y、z 的型態分別會是 int、float64 與 string,批量宣告時也可以自動推斷型態,例如:
var (
    x = 10        // int 型態
    y = 3.14      // float32 型態
    z = "Justin"  // string 型態
)
短變數宣告
在函式中,想要定義變數值的場合,可以使用短變數宣告,例如:
x := 10
y := 3.14
z := "Justin"
如果 x 是首次定義,就等於是宣告變數並指定值。上例也可以寫成一行:
x, y, z := 10, 3.14, "Justin"
由於 Go 的函式外,每個語法都必須以關鍵字開始,因此短變數宣告不能在函式外使用。
var 宣告的變數名稱不可重複,然而,短變數宣告時,若同一行內有新宣告了另一變數,就可以重複宣告已存在的變數,例如,以下是合法的,因為使用 := 時有一個新的 y 變數:
var x = 10
x, y :=  20, 30
此時,並沒有建立一個新的 x 變數,只是將新值指定給 x 而已。
由於短變數宣告可以同時宣告變數並指定值,因此對於底下這類需求:
package main
import "fmt"
func main() {
    var x = true
    if x {
        fmt.Println(x)
    }
}
在上例,x 的範圍是整個 main,若改為底下,範圍就只會是 if 區塊:
package main
import "fmt"
func main() {
    if x := true; x {
        fmt.Println(x)
    }
}
類似地,for 之類的語法,也常運用短變數宣告。
(在數學上 A := B 的寫法,涵義是藉由 B 來定義 A,例如數學上若已經定義 x 以及 f(x),x := f(x) 表示用舊的 x 定義新的 x,這反而像是程式語言中的 x = f(x) 指定的概念,當然,數學上的符號與程式語言中的符號是有出入的,Go 在這邊只是借用了 := 來作為另一種變數宣告符號。)
調換變數值
在 Go 中,要調換兩變數的值很簡單,例如底下的程式執行過後,x 會是 20,而 y 會是 10:
var x = 10
var y = 20
x, y = y, x
基本常數宣告
如一開始談到的,在 Go 中寫下的 10、3.14、true、"Justin" 等稱之為常數(Constant),常數宣告可給予這些常數識別名稱,要給予名稱時使用的是 const 關鍵字,例如:
const x = 10
正如〈認識預定義型態〉中談過的,10 會是一個整數常數,不過型態未定,如果要定義一個常數的型態,可以使用 int32()、int64() 之類的函式進行型態轉換,或者是在使用 const 宣告常數名稱時指定型態,例如:
const x int32 = 10
這邊的 10 就是 int32 型態了,注意,這邊的 x 並不是一個變數,而是一個識別名稱罷了,因此,會說 x 常數的型態是 int32,而不能說 x 變數的型態是 int32。
如果有多個常數要宣告,也可以批量宣告,例如:
const (
    x = 10
    y = 3.14
    z = "Justin"
)
再次地,x、y、z 分別是未定型態的整數、浮點數與字串常數(而不是 int、float64、string 這三個 Go 中定義的型態),如果你想要讓他們為已定義型態的整數、浮點數與字串常數,可以在宣告時指定型態:
const (
    x int = 10
    y float32 = 3.14
    z string = "Justin"
)
由於常數並非變數,因此,宣告了常數並不一定要用到,底下的程式不會發生錯誤:
package main
import "fmt"
func main() {
    const (
        x = 10
        y = 3.14
        z = "Justin"
    )
    fmt.Println(x)
    fmt.Println(y)
}
常數運算式
由於常數可以是未定型態,因此一個有趣的地方就是,像 2 + 3.0、15 / 4、15 / 4.0 這樣的常數運算式,該怎麼在編譯時期決定它們的值?答案是根據運算式中的常數運算元是整數、rune(單引號括住的常數)、浮點數或複數來決定,如果運算式中包括了越後面的常數,就會用它來決定。
因此,2 + 3.0 會是未定型態的浮點數 5.0,15 / 4 會是未定型態的整數 3,然而,15 / 4.0,會是浮點數型態的 3.75,在規格書的〈Constant expressions〉中,列出了說明以及一些範例,例如:
const a = 2 + 3.0          // a == 5.0   (untyped floating-point constant)
const b = 15 / 4           // b == 3     (untyped integer constant)
const c = 15 / 4.0         // c == 3.75  (untyped floating-point constant)
const Θ float64 = 3/2      // Θ == 1.0   (type float64, 3/2 is integer division)
const Π float64 = 3/2.     // Π == 1.5   (type float64, 3/2. is float division)
const d = 1 << 3.0         // d == 8     (untyped integer constant)
const e = 1.0 << 3         // e == 8     (untyped integer constant)
const f = int32(1) << 33   // illegal    (constant 8589934592 overflows int32)
const g = float64(2) >> 1  // illegal    (float64(2) is a typed floating-point constant)
const h = "foo" > "bar"    // h == true  (untyped boolean constant)
const j = true             // j == true  (untyped boolean constant)
const k = 'w' + 1          // k == 'x'   (untyped rune constant)
const l = "hi"             // l == "hi"  (untyped string constant)
const m = string(k)        // m == "x"   (type string)
const Σ = 1 - 0.707i       //            (untyped complex constant)
const Δ = Σ + 2.0e-4       //            (untyped complex constant)
const Φ = iota*1i - 1/1i   //            (untyped complex constant)
現在,應該能明白,〈認識預定義型態〉中 math.MaxInt64 若不加上 int64,何以會 overflow 的錯誤了。
附帶一提的是,在 Go 中,模組中定義的名稱若要能在模組外可見,必須是首字大寫,而對於像 math.MaxInt64 這類的公用常數,可以定義在一個 .go 檔案之中,例如 math.MaxInt64,就是定義在一個 const.go 之中。
使用 iota 列舉
如果要需要列舉一些常數時,可以使用 iota,它每遇到一次 const,就會重置為 0,若它在批量常數宣告中使用時,第一次出現時的預設值是 0,每出現一次就遞增 1,例如:
const (
    x = iota   // 0
    y = iota   // 1
    z = iota   // 2
 )
因為 const 批量宣告時,若後面的值沒寫出,會使用前一個值設定,例如:
const (
    x = 1
    y      // 1
    z      // 1
 )
因此,如果是連續的列舉,只要寫一次 iota 就可以了,這表示後續的值,也都使用 iota,結果就是:
const (
    x = iota   // 0
    y          // 1
    z          // 2
 )
其實也可以這麼寫來列舉常數,只是比較麻煩:
const x, y, z = iota, iota, iota

