Skip to content

Go指針

Go 保留了指針,在一定程度上保證了性能,同時為了更好的 GC 和安全考慮,又限制了指針的使用。

創建

關於指針有兩個常用的操作符,一個是取地址符&,另一個是解引用符*。對一個變量進行取地址,會返回對應類型的指針,例如:

go
func main() {
   num := 2
   p := &num
   fmt.Println(p)
}

指針存儲的是變量num的地址

0xc00001c088

解引用符則有兩個用途,第一個是訪問指針所指向的元素,也就是解引用,例如

go
func main() {
  num := 2
  p := &num
  rawNum := *p
  fmt.Println(rawNum)
}

p是一個指針,對指針類型解引用就能訪問到指針所指向的元素。還有一個用途就是聲明一個指針,例如:

go
func main() {
   var numPtr *int
   fmt.Println(numPtr)
}
<nil>

*int即代表該變量的類型是一個int類型的指針,不過指針不能光聲明,還得初始化,需要為其分配內存,否則就是一個空指針,無法正常使用。要麼使用取地址符將其他變量的地址賦值給該指針,要麼就使用內置函數new手動分配,例如:

go
func main() {
   var numPtr *int
   numPtr = new(int)
   fmt.Println(numPtr)
}

更多的是使用短變量

go
func main() {
   numPtr := new(int)
   fmt.Println(numPtr)
}

new函數只有一個參數那就是類型,並返回一個對應類型的指針,函數會為該指針分配內存,並且指針指向對應類型的零值,例如:

go
func main() {
   fmt.Println(*new(string))
   fmt.Println(*new(int))
   fmt.Println(*new([5]int))
   fmt.Println(*new([]float64))
}

0
[0 0 0 0 0]
[]

禁止指針運算

在 Go 中是不支持指針運算的,也就是說指針無法偏移,先來看一段 C++代碼:

cpp
int main() {
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    int *p = &arr[0];
    cout << &arr << endl
         << p << endl
         << p + 1 << endl
         << &arr[1] << endl;
}
0x31d99ff880
0x31d99ff880
0x31d99ff884
0x31d99ff884

可以看出數組的地址與數字第一個元素的地址一致,並且對指針加一運算後,其指向的元素為數組第二個元素。Go 中的數組也是如此,不過區別在於指針無法偏移,例如

go
func main() {
   arr := [5]int{0, 1, 2, 3, 4}
   p := &arr
   println(&arr[0])
   println(p)
   // 試圖進行指針運算
   p++
   fmt.Println(p)
}

這樣的程序將無法通過編譯,報錯如下

main.go:10:2: invalid operation: p++ (non-numeric type *[5]int)

TIP

標准庫unsafe提供了許多用於低級編程的操作,其中就包括指針運算,前往標准庫-unsafe了解細節。

new 和 make

在前面的幾節已經很多次提到過內置函數newmake,兩者有點類似,但也有不同,下面復習下。

go
func new(Type) *Type
  • 返回值是類型指針
  • 接收參數是類型
  • 專用於給指針分配內存空間
go
func make(t Type, size ...IntegerType) Type
  • 返回值是值,不是指針
  • 接收的第一個參數是類型,不定長參數根據傳入類型的不同而不同
  • 專用於給切片,映射表,通道分配內存。

下面是一些例子:

go
new(int) // int指針
new(string) // string指針
new([]int) // 整型切片指針
make([]int, 10, 100) // 長度為10,容量100的整型切片
make(map[string]int, 10) // 容量為10的映射表
make(chan int, 10) // 緩沖區大小為10的通道

Golang學習網由www.golangdev.cn整理維護