go 函数或者方法参数调用的过程

前言

最近做项目,使用go开发,但是在发生函数调用传参数时,对指针的指针的传递有难以理解的代码,就此分析过程。尤其是对于多重指针作为参数,而且对于一些内置函数的修改逻辑也需深入的理解。

1. demo

package slice_demo

import (
	"fmt"
	"testing"
)

func TestSliceCall(t *testing.T) {
	s := make([]int, 1, 10)
	fmt.Printf("1.---- %p %p %v\n", &s, s, s)
	a := append(s, 2, 3)
	fmt.Printf("1.---- %p %p %v\n", &a, a, a)
	changeSlice(a)
	changeSlicePoint(&a)
	fmt.Println(a, s)
}

func changeSlice(b []int) {
	b = append(b, 5, 6)
	b[0] = 111
	fmt.Printf("2.---- %p %p %v\n", &b, b, b)
}

func changeSlicePoint(p *[]int) {
	*p = append(*p, 10, 12)
	fmt.Printf("3.---- %p %p %p %v\n", &p, p, *p, p)
}

从demo看,有2种方式传参数修改切片的值,有下标修改,有append修改,结果有点出乎我们日常逻辑,结果如下

=== RUN   TestSliceCall
1.---- 0xc000118090 0xc000154140 [0]
1.---- 0xc0001180d8 0xc000154140 [0 2 3]
2.---- 0xc000118120 0xc000154140 [111 2 3 5 6]
3.---- 0xc000100028 0xc0001180d8 0xc000154140 &[111 2 3 10 12]
[111 2 3 10 12] [111]
--- PASS: TestSliceCall (0.00s)
PASS

可以看到append后的指针跟append前的切片是一样的,切片本身是引用类型,实现逻辑是数组,且是同一个数组(没扩容,且内存地址一样),但是值不一样。

而且切片在传入函数参数后,通过append并没有修改 传入的参数切片引用,可以通过下标修改;但是通过切片指针通过append却可以修改,原理是什么😅

 

2. 分析

2.1 先分析append的情况

结合这2行打印分析,append的过程

可以看到创建了2个变量(栈的引用) ,所以分配了2个内存地址,同时指向同一个数组(因为切片本身是指针),然而s和a的值却不一样。那么这是什么原因?实际上数组的内存地址仅仅是数组开始的内存地址,数组是连续的内存空间,是一个初始地址+offset或者position定位。看slice结构体可以明白,实际上内存地址后面的值已经被改掉了。

2.2 slice的结构体

type slice struct {
	array unsafe.Pointer
	len   int
	cap   int
}

slice.go定义了结构体,实际上slice是数组指针与len cap组成的,slice的扩容就是创建复制数组 ,修改len和cap。

2.3 slice直接传入函数参数

实际上append未生效,并不是未生效,已经修改了数组后面的连续内存的值了,只是因为没有对原始的变量赋值,没有修改len与cap,因为切片的结构体slice是基本数据类型,内存拷贝,是2个结构体,所以读取值是没变的。

分析原理画成图,跟实际结果符合。

 

 

2.4 slice传入函数指针

实际上切片没必要使用指针,因为切片本身就是指针,很多教程也推荐切片不使用指针,直接用;但是指针却有特殊的意义,可以修改传入的参数的数据值。

 

因为传入的切片的指针,所以p可以认为是a,因为是a的指针内存地址,操作a的指针内存地址就等于操作变量a,所以对*p赋值,可以修改a的值。

2.5 切片操作相互影响 

 因为切片的实现是数组,因为是指针,所以变量的修改会相互影响。这个就很容易理解了

总结

这里的问题是切片本身是指针,如果再加入指针,就是指针的指针,很难理解。而且再结合函数的参数,本身函数的参数是一个引用,栈变量自己又会分配内存地址,就更难理解了😅。这里的关键还有切片是一个结构体存储的,但是结构体又是内存值拷贝,而非内存地址引用。实际上可以结合内存分配的流程结合函数的入栈出栈,外加参数的存储结构很容易就明白原理了。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值