指针是一个用来指示一个内存地址的变量,一个指针变量指向了一个值的内存地址。Go 语言也为我们提供了控制数据结构的指针的能力,同时不像 C/C++ 中指针那么灵活,在 Go 语言中我们不能进行指针运算。因此 Go 语言中指针相对比较容易学习。

语法

Go 语言的取地址符是 & ,放到一个变量前使用就会返回相应变量的内存地址。

  1. var name Type = value
  2. // ①
  3. var p *Type
  4. p = &name
  5. // ②
  6. var p = &name
  7. // ③
  8. p := &name

对于变量 var 始终有 var == *(&var) 。在 fmt.Printf 函数中,指针的格式化标识符为 %p

  1. package main
  2. import "fmt"
  3. func main() {
  4. var v = 5
  5. var p *int
  6. p = &v
  7. fmt.Printf("v: %d, p: %p\n", v, p)
  8. *p = v + 1
  9. fmt.Printf("v: %d, p: %p\n", v, p)
  10. }
  11. // 输出:
  12. // v: 5, p: 0xc00000a0c8
  13. // v: 6, p: 0xc00000a0c8

也可以使用 new 方法来创建指针变量: p := new(Type) ,例如:

  1. str := new(string)
  2. *str = "Hello, pointer!"
  3. fmt.Println(*str)

指针的一个高级应用是你可以传递一个变量的引用(如函数的参数),这样不会传递变量的拷贝。指针传递是很廉价的,只占用 4 个或 8 个字节。当程序在工作中需要占用大量的内存,或很多变量,或者两者都有,使用指针会减少内存占用和提高效率。被指向的变量也保存在内存中,直到没有任何指针指向它们,所以从它们被创建开始就具有相互独立的生命周期。

限制

我们不能将指向 A 类型变量的指针赋值给 B 类型的指针变量:

  1. var y float32 = 5.0
  2. var yP *int
  3. yP = &y // error: cannot use &y (type *float32) as type *int in assignment

不能得到一个文字或常量的地址,例如:

  1. const i = 5
  2. ptr := &i //error: cannot take the address of i
  3. ptr2 := &10 //error: cannot take the address of 10

不能对指针进行运算,来操作内存地址,例如: pointer + 2c = *p++ 。Go 语言中的指针保证了内存安全,更像是 Java、C# 等语言中的引用。

空指针

当一个指针被定义后没有分配到任何变量时,它的值为 nilnil 指针也称为空指针。 nil 在概念上和其它语言的 nullNonenilNULL 一样,都指代零值或空值。