这是我参与「第五届青训营 」笔记创作活动的第3天
Go中的函数参数都是通过值传递的,即传递的都是一个值的副本。
基本类型
func test(value int) {
println(&value)
}
func main() {
a := 1
test(a)
println(&a)
}
如下所示,上述代码打印变量地址,得到的是不同的地址,说明不是同一个变量了。
每个变量都拥有一个地址,这个地址代表变量在内存中的位置。Go中使用&来获取变量地址,例如下面代码,&a打印出变量a在内存中的地址
func main() {
a := 1
println(a) //1
println(&a) //0xc00004df68
}
打印出的值为:
指针可以接收变量地址,打印指针pointer后,打印出的是变量a的地址
pointer := &a
println(pointer)
或者
var p *int
p = &a
println(p)
打印结果同样为a的地址
由此可以得出:每个变量都有一个地址,指针的值对应的是变量的地址
获取指针的地址
println(&p) //0xc00004df68
对指针进行取值操作,打印出的是指针对应的变量地址的值
println(*p) //1
所以*和&是一对互补的操作,一个是取地址,一个是取出地址里的值。
通过指针可以修改指针所指向的地址的值
*p = 2
print(a) //2
一个指针变量可以指向任何一个值的内存地址。当一个指针被定义后但没有分配任何变量,它默认值为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)
}
地址的打印结果如下:传入方法前的参数和传入方法后的参数是不同的。证明方法传参是形参。如果是基本类型,则复制一个值,如果是引用类型,则开辟一个新的地址存储原有结构体对象的拷贝。因此,对传参的修改,不会影响原有的参数。
如果传参修改为指针,则修改参数相当于修改了对象本身
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)
}
将指针传入方法函数内部时,就不用再去开辟一块新内存存储对象的副本,属于内存优化的一种形式。