Go指针|青训营笔记

24 阅读2分钟

这是我参与「第五届青训营 」笔记创作活动的第3天

Go中的函数参数都是通过值传递的,即传递的都是一个值的副本。

基本类型

func test(value int) {
   println(&value)

}
func main() {
   a := 1
   test(a)
   println(&a)
}

如下所示,上述代码打印变量地址,得到的是不同的地址,说明不是同一个变量了。

image.png

每个变量都拥有一个地址,这个地址代表变量在内存中的位置。Go中使用&来获取变量地址,例如下面代码,&a打印出变量a在内存中的地址

func main() {
   a := 1
   println(a)  //1
   println(&a) //0xc00004df68

}

打印出的值为:

image.png

指针可以接收变量地址,打印指针pointer后,打印出的是变量a的地址

pointer := &a
println(pointer)

image.png

或者

var p *int
p = &a
println(p)

打印结果同样为a的地址

image.png

由此可以得出:每个变量都有一个地址,指针的值对应的是变量的地址

获取指针的地址

println(&p) //0xc00004df68

image.png

对指针进行取值操作,打印出的是指针对应的变量地址的值

println(*p) //1

所以*和&是一对互补的操作,一个是取地址,一个是取出地址里的值。

通过指针可以修改指针所指向的地址的值

*p = 2
print(a) //2

image.png

一个指针变量可以指向任何一个值的内存地址。当一个指针被定义后但没有分配任何变量,它默认值为nil

可以通过new方法创建指针

ptr := new(string)
*ptr = "指针"
fmt.Println(*str) 

结构体

代码定义了两个结构体,以及一个结构体方法,测试传入参数的地址。

type Animal struct {
   name string
}
type Food struct {
   name string
}

func (animal Animal) eat(food Food) {
   println("animal方法内地址:", &animal)
   println("food方法内地址为:", &food)
}

func main() {
   animal := Animal{"Dog"}
   food := Food{"meat"}
   animal.eat(food)
   println("animal地址为:", &animal)
   println("food地址为:", &food)
}

地址的打印结果如下:传入方法前的参数和传入方法后的参数是不同的。证明方法传参是形参。如果是基本类型,则复制一个值,如果是引用类型,则开辟一个新的地址存储原有结构体对象的拷贝。因此,对传参的修改,不会影响原有的参数。

image.png 如果传参修改为指针,则修改参数相当于修改了对象本身

func (animal *Animal) eat(food *Food) {
   println("animal方法内地址:", animal)
   println("food方法内地址为:", food)
}

func main() {
   animal := Animal{"Dog"}
   food := Food{"meat"}
   animal.eat(&food)
   println("animal地址为:", &animal)
   println("food地址为:", &food)
}

image.png 将指针传入方法函数内部时,就不用再去开辟一块新内存存储对象的副本,属于内存优化的一种形式。