问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

Go切片作为函数参数时的一些思考

发布网友 发布时间:2024-09-29 22:16

我来回答

1个回答

热心网友 时间:2024-10-10 02:47

原理

Go语言中的切片事实上是一个结构体,其运行时结构如下:

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

这一点非常重要,这也就意味着,将切片作为函数参数时,其传递机制与结构体传递机制一样,都是值传递,也即传递的是原切片的拷贝。

另外一个非常重要的点就是,切片结构体中的array是一个指针,意味着array的值是底层数组的地址,通过函数传参后,这个值依然没有改变。

因此可以看到,当把切片作为函数参数传递时,在函数中对切片进行某些修改操作,会影响到函数外的原始切片。

看个栗子

先看一段代码:

?func?main()?{?????var?arr?=?[]int{1,?2,?3,?4,?5}?????fmt.Printf("arr?pointer:?%p\n",?&arr)?????test(arr)?????fmt.Printf("arr:?%v\n",?arr)?}???func?test(data?[]int)?{?????fmt.Printf("data?pointer:?%p\n",?&data)?????data[0]?=?100?}

问题:

请问上述代码中arr pointer:与data pointer:的输出是相同的吗?

请问上述代码中arr:打印的结果是多少?也即函数中对切片的修改会不会影响到函数外的原切片?

答案:

输出中arr pointer:与data pointer:的值不相同,这很好理解,这是因为切片是值传递,传递给函数的时候,重新创建了一个新的切片结构体,那么二者的地址当然不一样了。

打印的结果是arr: [100 2 3 4 5],也就证明了对切片的修改会影响到原切片。也正是这个原因导致很多人误以为切片作为函数参数时是引用传递,其实这种理解是错误的。

再看个栗子

这个栗子与上面的栗子唯一不同的是,在函数体中对切片增加了一个append操作

?func?main()?{?????var?arr?=?[]int{1,?2,?3,?4,?5}?????fmt.Printf("arr?pointer:?%p\n",?&arr)?????test(arr)?????fmt.Printf("arr:?%v\n",?arr)?}??func?test(data?[]int)?{?????fmt.Printf("data?pointer:?%p\n",?&data)?????data?=?append(data,?100)?????data[0]?=?100?}

那么问题来了:

此时arr:打印的结果是什么?

答案:打印的是arr: [1 2 3 4 5],如果理解了上面阐述的原理,那么也很好理解这个答案。这是因为通过append函数扩充一个元素时,由于原切片的容量不足,导致底层数组需要扩容,而扩容后的底层数组的地址改变了,因此函数中的data的结构体中的array值改变了,而后的data[0] = 100语句操作的已经是新的底层数组了,因此也就与函数外的原切片中指向的底层数组不是同一个了。

最后

最后,我想说的是,如果你确定编写的函数需要将切片的修改影响到函数外的原始切片,那么你的函数参数应该使用指针。

希望现在你可以清楚地回答下面的问题了

?//?代码一?func?main()?{?????var?arr?=?[]int{1,?2,?3,?4,?5}?????fmt.Printf("arr?pointer:?%p\n",?&arr)?????test(&arr)?????fmt.Printf("arr:?%v\n",?arr)?}??func?test(data?*[]int)?{?????fmt.Printf("data?pointer:?%p\n",?data)?????(*data)[0]?=?100?}?//?代码二?func?main()?{?????var?arr?=?[]int{1,?2,?3,?4,?5}?????fmt.Printf("arr?pointer:?%p\n",?&arr)?????test(&arr)?????fmt.Printf("arr:?%v\n",?arr)?}??func?test(data?*[]int)?{?????fmt.Printf("data?pointer:?%p\n",?data)?????*data?=?append(*data,?100)?????(*data)[0]?=?100?}

问题:

请问上述代码中arr pointer:与data pointer:的输出是相同的吗?

请问上述代码中arr:打印的结果是多少?

彩蛋

附加一个小问题:

?var?arr?=?[]int{1,?2,?3,?4,?5}?fmt.Printf("arr?pointer:?%p\n",?arr)?fmt.Printf("arr?pointer:?%p\n",?&arr)

上面??代码中两行输出语句的区别是什么?

答案:对于切片来说,使用%p格式化输出时,如果前面不加取地址符,那么打印的是切片中第一个元素的地址;如果前面加上取地址符&,那么打印的是该切片的地址。

原文:https://juejin.cn/post/7096054655511658526

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
单位高温防护欠缺致员工中暑如何对待 狗狗为什么爱看视频 360浏览器怎么设置倍速播放 ...先讲女主的灵魂飘荡了一段时间,然后重生,请问是那本? 拯救者散热器怎么开 电脑如何一键还原系统电脑一键还原怎么操作 神舟笔记本电脑怎么重新设置神舟战神bios恢复出厂设置 神舟电脑恢复出厂设置神舟战神怎么恢复原厂系统 水泥楼梯如何铺木楼梯 家里面楼梯是水泥的不想铺地毯或者地砖还能铺什么 ...我用结构体指针当作结构体数组 在一个函数里参数是这个结构体指针... 苹果手机怎样开启照相机闪光灯? 周公解梦梦见青蛇绞在一起有很多 怎样在文件管理中找到微信记录? 如何查看小米手机里的微信聊天记录呢? ...机的火控雷达与苏-27系列战斗机最大区别是什么? 石家庄市不需要高考成绩和高中毕业证花钱就可以去的大学有哪几个? ...没有专科文凭只有高中毕业证,要提供出国前最高学历,这情况拿高中... ...拿到毕业证!不想读大学了! 这样高中毕业能找到工作吗!有那些... 高中文凭有用吗?高中毕业高薪就业去哪?高中毕业生学什么技术好赚钱?高 ... 猎杀潜航3操作(《猎杀潜航3》决战心得)介绍_猎杀潜航3操作(《猎杀潜航3... 猎杀潜航3怎么玩的好啊,那些敌船一直逃,我在后面一直追,躲来躲去,难... ...用wifi热点建立的无线,手机能收到可就是连接不上,但是同学建立的我就... 索爱W760和W395的价格是多少钱?女士用合适吗? W395为什么滑盖的时候,屏幕里的东西会移动啊 索爱w395型号手机的价钱? 索爱W395这款手机好不好用? 索爱w395 网络问题 急!!! 索爱W395九百块钱贵吗?是水货 索爱w395白屏的问题!急求解决, 挖坟地的时候挖出了人骨怎样摆成人形? 美国签证面签通关攻略!增加过签率的4个tips 如何提高美国留学签证通过率 美国签证面签好过吗 申请美国签证,不被拒签的几条秘诀你知道吗 windows 7 专业版32位系统 ps/2鼠标的驱动你有吗? USB驱动删除了 鼠标键盘用不了PS/2的鼠标插上也不顶用 电脑没有光驱... 笔记本电脑上的PS/2兼容鼠标内两个驱动程序文件误删除 导致笔记本现在... ps/2键盘和鼠标驱动你是怎么弄好的? 男友生日,我想亲自做顿烛光晚餐,什么餐点比较好呢 H3C3100交换机怎么设置才可以进入WEB页 女人下面变黑怎么办 私处为什么会黑 私密部位发黑是怎么回事 自动麻将机怎么样让两副牌全部下去 什么理财软件大平台 买票时可以自己选座位吗 用什么投资理财软件 什么理财软件利息多 盲沟有哪些