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