【Golang】切片的底层实现(关于slice调用append函数后分配新数组的问题)
创始人
2024-03-29 08:29:09

问题描述

今天在写代码的时候遇到一个很奇怪的现象,先看下面两段代码

func push(a []int, v int) {a[1] = 2a = append(a, v)
}
func main() {a := []int{0, 1, 2}push(a, 3)fmt.Println(a)
}

结果:[0 2 2]

func push(a []int, v int) {a = append(a, v)a[1] = 2
}
func main() {a := []int{0, 1, 2}push(a, 3)fmt.Println(a)
}

结果:[0 1 2]

乍一看这两段代码几乎一模一样,唯一的不同在于push函数中两行代码的顺序不一致

这两段代码中有两个问题

  1. 为什么第一段代码中赋值语句起到作用,append没有起到作用
  2. 为什么第二段代码中的赋值语句和append都没有起到作用

问题分析

第一个问题:为什么第一段代码中赋值语句起到作用,append没有起到作用

首先我们要清楚Go语言中不存在引用传递,即这里的a []int是值传递,我们不妨输出一下a的地址

在这里插入图片描述
可以看到函数内外的a并不是同一个切片,那么既然不是同一个切片,为什么在第一段代码中,修改了函数内的a,函数外的a也会发生改变呢?


这里我们需要了解go语言中切片是如何实现的

可以看下图,go语言中的切片实际上是对底层数组的一个view
切片由三部分组成,分别是指向底层数组的指针ptr切片的长度len底层数组的长度cap
在这里插入图片描述
由此就可以解释为何在第一段代码中修改函数内的切片,函数外的切片也会发生改变,两个切片虽然地址不同,但是它们两个的值是相同的,也就是说它们两个内部的ptr是相同的都指向同一个底层数组,所以修改其中一个,另外一个也就会随之改变。同理,在函数内append时,函数内部的切片len增加了,但由于是值传递,所以函数外部的切片len没有改变,因此函数内部的切片append不会引起函数外部的切片改变。

第二个问题:为什么第二段代码中的赋值语句和append都没有起到作用

首先关于append为什么没有起到作用,在上面已经解释过了,这里我们重点关注为什么赋值语句也没有起到作用

原因只有一句话:切片在添加元素时如果超越cap,那么就不再是对原数组的view,系统会重新分配更大的底层数组

继续分析之前的代码,在输出地址的基础上再输出切片的len和cap
在这里插入图片描述

可以看到,在执行append之前,切片的len等于cap,执行append后,切片的长度会超过cap,此时系统会重新分配更大的数组。观察输出可以发现,执行完append后切片的cap发生了变化,与我们的设想一致,系统重新分配了一个更大的数组给切片,切片的ptr指针指向了另一个数组,与函数外的切片不再指向同一个数组,因此在函数内修改切片的值的时候对函数外的切片就不会产生影响了

更进一步,我们将切片赋予一个较大的cap,使函数内的切片再执行append后len不会超过cap,观察此时的函数外的切片是否会发生变化

在这里插入图片描述

可以看到此时函数内的赋值语句成功修改了函数外的切片的值,因为此时函数内的切片执行append后,切片的len没有超过cap,并不会分配新数组,因此后面再执行赋值语句时修改的还是函数外的数组

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...