指针是一个用来指示一个内存地址的变量,一个指针变量指向了一个值的内存地址。Go 语言也为我们提供了控制数据结构的指针的能力,同时不像 C/C++ 中指针那么灵活,在 Go 语言中我们不能进行指针运算。因此 Go 语言中指针相对比较容易学习。
语法
Go 语言的取地址符是 &
,放到一个变量前使用就会返回相应变量的内存地址。
var name Type = value
// ①
var p *Type
p = &name
// ②
var p = &name
// ③
p := &name
对于变量 var
始终有 var == *(&var)
。在 fmt.Printf
函数中,指针的格式化标识符为 %p
。
package main
import "fmt"
func main() {
var v = 5
var p *int
p = &v
fmt.Printf("v: %d, p: %p\n", v, p)
*p = v + 1
fmt.Printf("v: %d, p: %p\n", v, p)
}
// 输出:
// v: 5, p: 0xc00000a0c8
// v: 6, p: 0xc00000a0c8
也可以使用 new
方法来创建指针变量: p := new(Type)
,例如:
str := new(string)
*str = "Hello, pointer!"
fmt.Println(*str)
指针的一个高级应用是你可以传递一个变量的引用(如函数的参数),这样不会传递变量的拷贝。指针传递是很廉价的,只占用 4 个或 8 个字节。当程序在工作中需要占用大量的内存,或很多变量,或者两者都有,使用指针会减少内存占用和提高效率。被指向的变量也保存在内存中,直到没有任何指针指向它们,所以从它们被创建开始就具有相互独立的生命周期。
限制
我们不能将指向 A 类型变量的指针赋值给 B 类型的指针变量:
var y float32 = 5.0
var yP *int
yP = &y // error: cannot use &y (type *float32) as type *int in assignment
不能得到一个文字或常量的地址,例如:
const i = 5
ptr := &i //error: cannot take the address of i
ptr2 := &10 //error: cannot take the address of 10
不能对指针进行运算,来操作内存地址,例如: pointer + 2
、 c = *p++
。Go 语言中的指针保证了内存安全,更像是 Java、C# 等语言中的引用。
空指针
当一个指针被定义后没有分配到任何变量时,它的值为 nil
。 nil
指针也称为空指针。 nil
在概念上和其它语言的 null
、 None
、 nil
、 NULL
一样,都指代零值或空值。