Go开发03 切片彻底研究(三)

这篇根据底层分析切片

切片实际对应的是一个结构

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

三个成员依次是数据指针长度容量。现在我们主要来看函数调用

func test_slice(b []int) {
	b = append(b, 100)
	fmt.Println(b)
}
func main() {
	//创建切片a,长度为0,容量为10
	var a = make([]int, 0, 10)
    
	//追加5个元素之后,长度为5,容量为10
	a = append(a, 1, 2, 3, 4, 5)

	//调用函数
	test_slice(a)
	fmt.Println(a)
}

代码比较简明,我们重点看实参形参

如前文所述,切片对应的是一个结构,那么可以认为把实参a传过去,相当于将a的结构体传过去,这一步理解至关重要。

接着,形参实参一结合,b就得到一份a的结构副本。由于当前a容量还有5个元素,因此追加100之后,没有扩容。所谓的扩容主要就是指结构成员的array指针发生变化

因此b和a依然共享同一段切片内存。打印结果b=[]int{1,2,3,4,5,100},但是打印a却等于a=[]int{1,2,3,4,5},没有发生变化,这是为什么呢?
原因就在于,切片b追加之后,它的长度len也跟着变化。但是原来a的结构体内部的len并没有变化¹,因此为了能看到a确实共享同一个切片,需要将a的切片长度进行修正

¹补充:如果学过C语言,我们想像有一个结构类型

struct Slice{
  int a;
  int b;
  int c;
};

当将结构传值传过去时,成员a,b,c就复制一个副本,因此,如果副本发生变化和原结构一点都没关系。类比切片的结构,len是一个int,也是一样只是传个副本...

test_slice(a);
a=a[:6] //修正a的长度
fmt.Println(a)

再次打印可以看到1,2,3,4,5,100。

扩容导致指针变化

现在我们看一下扩容的例子

func test_slice(b []int) {
	//追加三个元素,导致切片扩容
	b = append(b, 20,21,22)
	fmt.Println(b)
}
func main() {
	//创建切片a,长度为0,容量为10
	var a = make([]int, 0, 10)
    
	//追加8个元素之后,长度为8,容量为10
	a = append(a, 1, 2, 3, 4, 5, 6, 7, 8)

	//调用函数
	test_slice(a)
	fmt.Println(a)
}

分析:

调用函数后,由于追加3个元素,而原切片只剩2个元素,因此需要切片扩容。所谓切片扩容用一个词来形容就是“另起炉灶”,和原切片完全脱离关系,因为是在新内存中创建的。

那么b结构体中的array指针发生变化,指向新地址值。而原切片由于脱离关系不受干扰,还是原样。
结果:
b=[]int{1,2,3,4,5,6,7,8,20,21,22}
a=[]int{1,2,3,4,5,6,7,8}

想通过函数改变原切片

如果就想通过函数改变原切片怎么办呢?上面的例子我们可以看出,实际是一个值传递的问题,我们能不能牢牢的控制结构内部的指针还属于a呢?自然就想到将切片的指针传过去,相当于C语言中将结构体的地址传过去

//形参传为切片的地址
func test_slice(b *[]int) {
	//追加三个元素,导致切片扩容
	*b = append(*b, 20,21,22)
	fmt.Println(*b)
}
func main() {
	//创建切片a,长度为0,容量为10
	var a = make([]int, 0, 10)
	//追加8个元素之后,长度为8,容量为10
	a = append(a, 1, 2, 3, 4, 5, 6, 7, 8)

	//调用函数,传切片地址
	test_slice(&a)
	fmt.Println(a)
}

总结

完美的三篇文章!应对实际开发中绝大部分场景。

展开阅读全文

页面更新:2024-05-12

标签:切片   副本   指针   函数   长度   元素   容量   发生   结构   地址

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top