go语言指针类型的值也是一种值类型
今天观看bilibili幼麟实验室关于函数调用栈的时候看到一个例子,怕自己忘记函数调用栈的知识所以写一下,水平实在是很菜有问题还请指出谢谢啦。
例子1
func swap(a,b int) {
a,b=b,a
}
func main(){
a,b:=1,2
swap(a,b)
fmt.Println(a,b)
}
这种方式为什么没有实现两数对调呢,或许用C语言的实参形参来解释很容易:因为交换的两个数字是入参的两个形参,所以影响不到实参。
事实上在go语言函数调用栈里面每个函数有其独立的栈帧。如上面这两个函数main和swap,他们就有其自己的栈帧,栈帧(stack frame)是分配给整个函数的栈空间,用于存放该函数的参数、调用函数返回值、局部变量等信息,如下图。
当执行到swap函数的a,b=b,a的时候,修改交换的是参数args里面值,并没有修改到局部变量locals的值。故而fmt输出输出的时候没有成功。
例子2
func swap(a,b *int) {
a,b=b,a
}
func main(){
a,b:=1,2
swap(&a,&b)
fmt.Println(a,b)
}
看了视频我拍大腿,哦豁原来原理是这样的,那我交换两个参数的地址不就行了吗,于是我试了试上面的代码,发现还是不行,思考了一下发现原因是因为我将上个例子中讲到的局部变量a和b的两个变量的地址作为一串地址字符传到了参数args的位置,于是swap交换的时候,swap内:指针a的地址的值=指针b的地址的值;指针b地址的值=指针a地址的值,发生的位置都是在参数args的位置,所以并没有影响到主函数内的局部变量a,b的值
例子3
func swap(a,b *int) {
*a,*b=*b,*a
fmt.Println(a,b)
}
func main(){
a,b:=1,2
swap(&a,&b)
fmt.Println(a,b)
fmt.Println(&a,&b)
}
这次就没问题了,因为在swap内部执行到* a,* b=* b,* a的时候,将a,b指针变量地址取值,拿到了main栈帧中局部变量里面a,b所在内存地址里面的值,然后将他们拿出来进行平行赋值实际上就是影响到了main函数中a,b的值。