這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
目錄 [−]
- 常量
- 變數
- 變數聲明簡化
- 靜態類型和動態類型
本文介紹Go語言的常量和變數的語言細節。
常量
只有數實值型別和字串類型才可以作為常量。
數實值型別包括 布爾類型、rune類型、各種整型、浮點類型、複數。
常量值既可以是數實值型別的字面量,也可以是字串字面量,以及常量的等價形式, 如:
- 常量運算式, 如
4 * 5
- 轉換結果是常量, 如
int(10.0)
- 內建函數的傳回值, 如
unsafe.Sizeof、cap、len
- 複數、實數和虛數的應用
true和false賦值給bool類型的常量
- 內建的
iota
用變數賦值給常量是不允許的:
12 |
var vs = "hello world"const s = vs //錯誤 |
常量的命名還是遵循前一篇文章的介紹,所有你看到一些"奇怪"的常量名不要覺得奇怪:
12 |
const π = 3.1415926const Π = 3.1415926 |
常量可以不宣告類型(untyped), 它會根據常量值設定預設的類型,預設類型為:
- bool
- rune
- int
- float64
- complex128
- string
在需要類型的上下文中,常量可以隱式轉換成相應的類型:
123 |
var v1 int = ivar v2 float32 = ivar v3 complex64 = i |
注意不同類型的變數是不能轉換的:
你不能將一個不能隱式轉換成常量類型的值賦值給常量,比如下面的例子中2147483648.0不能賦值給int32, 溢出了:
1 |
const i2 int32 = 2147483648.0 |
Go對常量的底層實現有限制:
- Represent integer constants with at least 256 bits.
- Represent floating-point constants, including the parts of a complex constant, with a mantissa of at least 256 bits and a signed exponent of at least 32 bits.
- Give an error if unable to represent an integer constant precisely.
- Give an error if unable to represent a floating-point or complex constant due to overflow.
- Round to the nearest representable constant if unable to represent a floating-point or complex constant due to limits on precision.
聲明多個變數的時候可以將聲明放在一起:
1234 |
const (i = 1s = "hello word") |
或者將多個常量的定義放在一行中:
1 |
const i1, i2, i3 = 0, 1, "hello world" |
常量也可以定義在函數中:
123 |
func G() { const t = 100} |
變數
變數代表一個值的儲存位置,每個值都有類型。
變數在聲明的時候如果同時有賦值操作,那麼類型可以省略,因為可以根據值推斷出來:
12 |
var i1 int = 100var i2 = 100 |
類似於常量定義,你可以同時聲明多個變數:
1234 |
var ( i3 = 120 i4 = "hello world") |
或者一行聲明多個變數:
12 |
var i5, i6, i7 = 100, "hello world", truevar i8, i9, i10 int |
在上面的例子中i8、i9、i10都是 int類型,所以將類型寫在最後面,下面的寫法是不允許的:
1 |
var i11 int, i12 int, i13 int //錯誤 |
下面的語句也是非法的,因為聲明的變數和賦值列表的數值數量必須一樣:
12 |
var i14, i15, i16 = 100, 200 //錯誤var i17, i18, i19 int = 100, 200 //錯誤 |
變數聲明簡化
如果變數在聲明的時候同時初始化,那麼它就可以簡化。
比如
1 |
var i1, i2 = 100, "hello world" |
可以簡化為
1 |
i1, i2 := 100, "hello world" |
記住,這個簡寫方法只能用在函數中,函數之外的變數聲明不能簡寫,下面的寫法是錯誤的。
123456 |
package mains := "中國"func main() {} |
不像普通的變數聲明,簡寫方式聲明的變數可以"重新聲明"已有變數,只要保證有一個新的變數在變數列表中即可,當然“重新聲明”的變數和原有變數的類型相同。
看下面的例子就容易理解了:
123456 |
func main() {var f *os.Filef, err := os.Open("dive-into-go.pdf")fmt.Println(f, err)} |
這個例子中f變數重新被聲明了,程式正常編譯,沒有錯誤,這是因為err是新的變數。
下面這個例子就編譯不過,因為第4行沒有新的變數定義。
1234567 |
func main() {var f *os.Filevar err errorf, err := os.Open("dive-into-go.pdf")fmt.Println(f, err)} |
不能用簡寫方法賦值給一個結構體的欄位(field):
12345678910 |
type MyFile struct {var F *os.File}func main() {var mf MyFile//var err errormf.F, err := os.Open("dive-into-go.pdf")fmt.Println(f, err)} |
注意,簡寫方法有時候會迷惑你,因為它可能shadow一個變數,而且正常編譯通過:
1234567 |
x := 100func() { x := 200 fmt.Println(x) //200}()fmt.Println(x) //100 |
在上面的例子中,如果本意是通過一個方法修改變數x的值為200的話,最終列印結果可能是100,因為第三行實際是聲明了一個新的變數。
你可以通過vet工具檢查代碼中是否包含shadow的代碼:
1 |
go tool vet -shadow main8.go |
輸出結果為:
1 |
main8.go:8: declaration of x shadows declaration at main8.go:6: |
變數和常量都可以定義在函數內或者包下,但是如果函數內的變數沒有被使用,則會編譯出錯,這是Go語言有意這樣設計的。包下的變數和常量,函數內的常量沒有這個限制。
參考
* http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/index.html#short_vars
靜態類型和動態類型
靜態類型(static type)是變數聲明的時候的宣告類型,在變數聲明、new方法建立對象時或者結構體(struct)的元素的類型定義,參數類型等。
介面(interface)類型的變數還有一個動態類型,它是運行時賦值給這個變數的具體的值的類型(當然值為nil的時候沒有動態類型)。一個變數的動態類型在運行時可能改變,
這主要依賴它的賦值。
1234 |
var x interface{} // x 為零值 nil,靜態類型為 interface{}var v *T // v 為零值 nil, 靜態類型為 *Tx = 42 // x 的值為 42,動態類型為int, 靜態類型為interface{}x = v // x 的值為 (*T)(nil), 動態類型為 *T, 靜態類型為 *T |