變量的命名
變量名 必須以一個(gè) 字母或下劃線開頭 ,后面可以跟任意數(shù)量的字母、數(shù)字或下劃線,在 Go 語言中,變量名區(qū)分大小寫字母。當(dāng)然,上述的命名規(guī)則在命名 函數(shù)名 、 常量名 、 類型名 、 語句標(biāo)號 和 包名 等都適用。
特別注意的是,在 Go 中有 25
個(gè)關(guān)鍵字不能用于定義名字,它們分別是:
關(guān)鍵字 | 作用 |
---|---|
eak | 用于跳出循環(huán) |
default | 用于選擇結(jié)構(gòu)的默認(rèn)選項(xiàng)(switch、select) |
func | 定義函數(shù) |
interface | 定義接口 |
select | Go語言特有的channel選擇結(jié)構(gòu) |
case | 選擇結(jié)構(gòu)標(biāo)簽 |
defer | 延遲執(zhí)行內(nèi)容(在函數(shù)結(jié)尾的時(shí)候執(zhí)行) |
go | 并發(fā)執(zhí)行 |
map | 定義map類型 |
struct | 定義結(jié)構(gòu)體 |
chan | 定義channel |
else | 選擇結(jié)構(gòu) |
goto | 跳轉(zhuǎn)語句 |
package | 包 |
switch | 選擇結(jié)構(gòu) |
const | 定義常量 |
fallthrough | 如果case帶有fallthrough,程序會(huì)繼續(xù)執(zhí)行下一條case,不會(huì)再判斷下一條case的值 |
if | 選擇結(jié)構(gòu) |
range | 從slice、map等結(jié)構(gòu)中取元素 |
type | 定義類型 |
continue | 跳過本次循環(huán) |
for | 循環(huán)結(jié)構(gòu) |
import | 導(dǎo)入包 |
return | 返回 |
var | 定義變量 |
當(dāng)然,除了上面所說的 25
個(gè)關(guān)鍵字之外,還有大約 30
多個(gè)預(yù)定義的名字,具體如下。
內(nèi)建常量:
true false iota nil
內(nèi)建類型:
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
float32 float64 complex128 complex64
bool byte rune string error
內(nèi)建函數(shù):
make len cap new append copy close delete
complex real imag
panic recover
這些內(nèi)部預(yù)先定義的名字并不是關(guān)鍵字,你可以在定義中重新使用它們,但在普通情況下并 不推薦 這么做,免得引起語義混亂。在習(xí)慣上,Go語言程序員推薦使用 駝峰式 命名。
變量的聲明
Go 語言主要有四種類型的聲明語句:var(聲明變量) 、 const(聲明常量) 、 type(聲明類型) 和 func(聲明函數(shù)) 。
接下來我們就詳細(xì)講一講幾種聲明變量的方法。
第一種聲明方法 :一行一個(gè)變量
var < name > < type >
其中 var
是關(guān)鍵字, name
是變量名, type
是類型。
當(dāng)然,你也可以在聲明時(shí)給定該變量的初始值:
var < name > < type > = < expression >
如果你在聲明變量的時(shí)候只指定了其類型, Go 會(huì)自動(dòng)給你的變量初始化為默認(rèn)值。例如 string
類型會(huì)初始化為空字符串 ""
, int
類型會(huì)初始化為 0
, float
會(huì)初始化為 0.0
, bool
類型會(huì)初始化為 false
, 接口
和 引用類型
和 指針類型
就初始化為 nil
, 數(shù)組
或 結(jié)構(gòu)體
等聚合類型對應(yīng)的默認(rèn)值是每個(gè)元素或字段都是對應(yīng)該類型的默認(rèn)值等。
你在已經(jīng)給定變量初始值的情況下,可以將類型 type
部分省略, Go 將根據(jù)初始化表達(dá)式 expression
來推導(dǎo)變量的類型:
var < name > = < expression >
下面演示了一行聲明一個(gè)變量的例子:
package main
import (
"fmt"
)
func main() {
// var < name > < type >
var name string
fmt.Println("name = ", name)
// var < name > < type > = < expression >
var pi float64 = 3.14
fmt.Println("pi = ", pi)
// var < name > = < expression >
var phone = "123456"
fmt.Println("phone = ", phone)
}
運(yùn)行該程序輸出為:
name =
pi = 3.14
phone = 123456
第二種聲明方法 :一組變量一起聲明
var (
< name > < type >
< name > < type >
...
)
上面的例子每個(gè)變量都要寫一行聲明,為了簡潔,我們可以修改成一組變量一起聲明的形式:
package main
import (
"fmt"
)
func main() {
// var (
// < name > < type >
// < name > < type >
// ...
// )
var (
name string
pi float64 = 3.14
phone = "123456"
)
fmt.Println("name = ", name)
fmt.Println("pi = ", pi)
fmt.Println("phone = ", phone)
}
當(dāng)然,運(yùn)行該程序會(huì)產(chǎn)生同樣的輸出。
第三種聲明方法 :短聲明,只能在函數(shù)內(nèi)
在函數(shù)內(nèi)部,有一種稱為簡短變量聲明語句的形式可用于聲明和初始化局部變量,變量的類型根據(jù)表達(dá)式來自動(dòng)推導(dǎo)。
< name > := < expression >
例如,下面的三條等價(jià)的語句:
phone := "123456"
var phone string = "123456"
var phone = "123456"
但要特別注意,短聲明 只能 用在函數(shù)內(nèi)部,在包級別的聲明不能使用短聲明,要使用關(guān)鍵字 var
進(jìn)行聲明。
第四種聲明方法 :一行聲明和初始化多個(gè)變量
var < name1 >, < name2 > < type > = < expression1 >, < expression2 >
下面是一行聲明和初始化多個(gè)變量的例子:
var i, j, k int // int, int, int
var ok, number = true, 1.2 // bool, float64
phone, city := "123456", "Beijing" // string, string
這種方法經(jīng)常用于變量之間的交換:
var a int = 1
var b int = 2
b, a = a, b
第五種聲明方法 :通過 new 創(chuàng)建指針變量
一般變量分為兩種,上面說過的那些存放數(shù)據(jù)本身的 普通變量 和存放數(shù)據(jù)地址的 指針變量 。
例如,下面的例子,用 var x int
聲明語句聲明的是一個(gè) x 普通變量,那么 &x
表達(dá)式所代表的就是一個(gè)指向 x 普通變量的指針變量,即 &x
為存放 x 數(shù)據(jù)的地址,其對應(yīng)的數(shù)據(jù)類型為 *int
。而 *p
表達(dá)式所代表的是對應(yīng) p 指針指向的變量的值,即 x 的值。
package main
import (
"fmt"
)
func main() {
x := 1
p := &x // p, of type *int, points to x
fmt.Println("p = ", p) // "0xc0000aa058"
fmt.Println("*p = ", *p)// "1"
*p = 2 // equivalent to x = 2
fmt.Println("x = ", x) // "2"
}
運(yùn)行該程序會(huì)輸出下面的類似結(jié)果,其中第一行輸出的是存放普通變量 x
的地址,該值不固定:
p = 0xc0000aa058
*p = 1
x = 2
而這里講的 new
函數(shù)是 Go 里的一個(gè)內(nèi)建函數(shù)。
使用表達(dá)式 new(Type)
將創(chuàng)建一個(gè) Type
類型的匿名變量,初始化為 Type
類型的零值,然后返回變量地址,返回的指針類型為 *Type
。
package main
import (
"fmt"
)
func main() {
p := new(int) // p, *int 類型, 指向匿名的 int 變量
fmt.Println("*p = ", *p)// 匿名的 int 變量零值為 "0"
*p = 2 // 設(shè)置 int 匿名變量的值為 2
fmt.Println("*p = ", *p)// "2"
}
該程序輸出如下:
*p = 0
*p = 2
用 new
創(chuàng)建變量除了不需要聲明一個(gè)臨時(shí)變量的名字外,和普通變量聲明語句方式創(chuàng)建變量沒有什么區(qū)別。
第六種 :make 函數(shù)創(chuàng)建 slice、map 或 chan 類型變量
在 Go 語言中可以使用 make
函數(shù)創(chuàng)建 slice、map 或 chan 類型變量:
var mySlice = make([]int, 8)
var myMap = make(map[string]int)
var myChan = make(chan int)
slice、map 和 chan 是 Go 中的引用類型,它們的創(chuàng)建和初始化,一般使用 make。特別的, chan 只能用 make 。slice 和 map 還可以簡單的方式:
mySlice := []int{0, 0}
myMap := map[string]int{}
特別注意
變量或者常量都只能聲明一次,特別注意短聲明,例如下面的示例, a
和 b
都已經(jīng)使用短聲明了,再使用一次短聲明就是錯(cuò)誤的。但是,如果短聲明中僅有一些變量在相同的詞法域聲明過了,那么短變量聲明語句對這些已經(jīng)聲明過的變量就只有賦值行為。
a, b := 1, 2
...
a, b := 1, 3 // error
a, b = 1, 3 // ok
a, c := 1, 3 // ok
當(dāng)然, 匿名變量 (也稱作占位符,或者空白標(biāo)識符,用下劃線表示)可以聲明多次。匿名變量有三個(gè)優(yōu)點(diǎn):
- 不分配內(nèi)存,不占用內(nèi)存空間
- 不需要你為命名無用的變量名而糾結(jié)
- 多次聲明不會(huì)有任何問題
通常我們用匿名接收 必須接收,但是又不會(huì)用到的值 ,例如:
// array of 3 integers
var a [3]int
// Print the elements only.
for _, v := range a {
fmt.Printf("%dn", v)
}
變量的生命周期
變量的生命周期指的是在程序運(yùn)行期間變量有效存在的時(shí)間段。對于在包一級聲明的變量來說,它們的生命周期和整個(gè)程序的運(yùn)行周期是一致的。而相比之下,局部變量的生命周期則是從創(chuàng)建的聲明語句開始,直到該變量不再被引用為止,然后變量的存儲(chǔ)空間可能被回收。函數(shù)的參數(shù)變量和返回值變量都是局部變量。它們在函數(shù)每次被調(diào)用的時(shí)候創(chuàng)建。
一個(gè)循環(huán)迭代內(nèi)部的局部變量的生命周期可能超出其局部作用域。同時(shí),局部變量可能在函數(shù)返回之后依然存在。
編譯器會(huì)自動(dòng)選擇在棧上還是在堆上分配局部變量的存儲(chǔ)空間,但可能令人驚訝的是,這個(gè)選擇并不是由用 var
還是 new
聲明變量的方式?jīng)Q定的。
評論
查看更多