Slice是go中的一个基本操作
本文主要演示切片传参对自身的影响
系统环境
- Ubuntu19.10
- IDEA Goland
- GO Version 1.14.0
##简介
切片的结构
type SliceHeader struct {
Data uintptr // 指向底层数组的指针
Len int // 表示当前切片的长度
Cap int // 表示当前切片的容量
}
切片数据结构就是上述这样,这里就不再赘述了,如果想了解详细的切片的操作请参考下面:
超级跳转
切片特性
- 切片可以自动扩容
- Len的值总是小于等于Cap,且都大于等于零
- 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. 总结
- 当切片传参时,是以指针的形式传递的
- 当切片A扩容时,就回产生新的切片,即使重新赋值,切片A也不再是切片A了