关于Golang中Slice(切片) 传参分析

Slice是go中的一个基本操作
本文主要演示切片传参对自身的影响

系统环境

  1. Ubuntu19.10
  2. IDEA Goland
  3. GO Version 1.14.0
    ##简介

切片的结构

type SliceHeader struct {
	Data uintptr   // 指向底层数组的指针
	Len  int             // 表示当前切片的长度
	Cap  int            // 表示当前切片的容量
}

切片数据结构就是上述这样,这里就不再赘述了,如果想了解详细的切片的操作请参考下面:
超级跳转

切片特性

  1. 切片可以自动扩容
  2. Len的值总是小于等于Cap,且都大于等于零
  3. Data 可能会变
声明:切片传参本身就是指针,本文不讨论二级,多级指针的情况

1.切片不扩容

func main() {
		a := make([]int, 10, 10)
		fmt.Printf("fun return %p \nnew value a = %d\n", newA,newA)
		fmt.Printf("oldP = %p\nold value a = %d\n", a,a)
}
// 没有发生扩容且传入指针
func sliceA(a []int) []int {
	a[1] = 1
	return a
}

输出结果如下:
			fun return 0xc000020050 
			new value a = [0 1 0 0 0 0 0 0 0 0]
			oldP = 0xc000020050
			old value a = [0 1 0 0 0 0 0 0 0 0]

上述初始化了一个int切片,长度为10,容量为10!
分析(敲黑板,划重点):
这里上述传入的切片其实我们反复的操作都是对同一个切片修改,看打印的指针就知道了我们再对同一个内存地址的东西操作。
原因:

golang中是值传递:这里的值传递不是说参数给了一个指针,
会自动获取指针指向的value进行操作,你传的是指针,那么函数参数的值就是指针。
再将切片传参时,其实传递的是指针。所以我们在函数内部操作的其实是同一个切片

** 如果你认为切片传递的值不会改变,那肯定是不了解切片是怎么扩容的我们下面继续看**

2. 切片发生扩容

func main() {
	b := make([]int, 10, 10)
	b[1] = 1
	fmt.Printf("slice b = %p\nnew value a = %d\n", b, b)
	returnB := sliceB(b)
	fmt.Printf("fun return %p \nnew value a = %d\n", returnB, returnB)
}

func sliceB(b []int) []int {
	b = append(b, 1)
	return b
}

输出结果:
		slice b = 0xc000020050
		new value a = [0 1 0 0 0 0 0 0 0 0]
		fun return 0xc000118000 
		new value a = [0 1 0 0 0 0 0 0 0 0 1]

同样初始化一个int切片,长度10,容量10!

前后两个切片值不同,指针不一样,这里切片追加了一个 int(1) ,
长度超出了容量,所以发生了扩容,
这时候发生了重新申请空间的情况导致此时系统中存在两个切片。
这时候切片b当然就和返回值 切片return不一样了

感兴趣的同学可以输出一下现在切片的容量是多少??????

3. 总结

  1. 当切片传参时,是以指针的形式传递的
  2. 当切片A扩容时,就回产生新的切片,即使重新赋值,切片A也不再是切片A了