要搞明白Go语言中的指针需要先知道3个概念:指针地址、指针类型和指针取值。
Go语言中的函数传参都是值拷贝,当我们想要修改某个变量的时候,我们可以创建一个指向该变量地址的指针变量。传递数据使用指针,而无须拷贝数据。类型指针不能进行偏移和运算。Go语言中的指针操作非常简单,只需要记住两个符号:&
(取地址)和*
(根据地址取值)。
比如下面的代码:
var a = 3
fmt.Printf("num is : %d, it's location in memory: %p\n", a, &a)
输出:
num is : 3, it's location in memory: 0xc000062080
可以看到&a输出了a的内存地址。
你可以将&a赋值给一个变量,然后观察这个变量的类型,使用reflect.TypeOf()
方法:
var a = 3
b := &a
fmt.Println(reflect.TypeOf(b))
输出:
*int
可以看到&a的返回类型是 *int。
我们可以将一个变量的内存地址放在一个叫做指针的特殊数据类型中,声明一个指针的方式如下:
var p *int
然后我们可以使用p去指向一个内存地址:
p = &a
那么我们如何通过指针来获取对应内存地址的值呢,这也是有办法的。你可以在指针类型前面加上 * 号(前缀)来获取指针所指向的内容,这里的 * 号是一个类型更改器。使用一个指针引用一个值被称为间接引用。
func main() {
//指针取值
a := 10
b := &a // 取变量a的地址,将指针保存到b中
fmt.Printf("type of b:%T\n", b)
c := *b // 指针取值(根据指针去内存取值)
fmt.Printf("type of c:%T\n", c)
fmt.Printf("value of c:%v\n", c)
}
输出如下:
type of b:*int
type of c:int
value of c:10
当一个指针被定义没有分配任何变量的时候,它的值为nil。
// 值传递x
func modify1(x int) {
x = 100
}
// 指针类型x
func modify2(x *int) {
*x = 100
}
func main() {
a := 10
modify1(a) // 此时的修改不会改变a的值,因为传递的是a的一个副本
fmt.Println(a) // 10
modify2(&a) // 传递了a的指针地址,并且接收参数是指针类型,所以会被修改
fmt.Println(a) // 100
}
对于任何一个变量val,如下表达式都是正确的:
var == *(&var)
有如下你需要注意的是,你不能获取到一个常量或者一个没有赋值操作的文字的内存地址:
const PI = 3.14
piP := &PI Cannot take the address of 'PI'
p2 := &3 Cannot take the address of '3'
package main
import "fmt"
func main() {
var p *string
fmt.Println(p)
fmt.Printf("p的值是%v\n", p)
if p != nil {
fmt.Println("非空")
} else {
fmt.Println("空值")
}
}
Go 默认使用按值传递来传递参数,也就是传递参数的副本。当我们想要修改某个变量的时候,我们可以创建一个指向该变量地址的指针变量。传递数据使用指针,而无须拷贝数据。类型指针不能进行偏移和运算。Go语言中的指针操作非常简单,只需要记住两个符号:(&
)(取地址)和(*
)(根据地址取值)
在对普通变量使用(&
)操作符取地址后会获得这个变量的指针,然后可以对指针使用(*
)操作,也就是指针取值。取地址操作符&和取值操作符*
是一对互补操作符,&
取出地址,*
根据地址取出地址指向的值。
&
)操作,可以获得这个变量的指针变量。*
)操作,可以获得指针变量指向的原变量的值。