求解一个 Go 数组问题

2022-08-24 10:33:37 +08:00
 rimutuyuan
func main() {
	var s []int
	for i := 0; i < 3; i++ {
		s = append(s, i)
	}

	modifySlice(s)

	fmt.Println(s)
}

func modifySlice(s []int) {
	s = append(s, 2048)
	s[0] = 1024
}

输出为什么是 1024 1 2 而不是 1024 1 2 2048

997 次点击
所在节点    问与答
9 条回复
RoninZc
2022-08-24 10:41:25 +08:00
golang 函数值传递
slice 底层结构 { len:长度, cap: 底层数组长度, *p 指针}

main 中的 slice 传递进 modifySlice ,实际是底层数组指针和长度信息的拷贝
在 s= append(s, 2048) 执行后 s 被重新赋值 p 内数据为 1, 2, 3, 2048 ,len 为 4
其后 0 号位置被修改为 1024 ,其中 s 没有被返回
执行结束后,main 函数中的 s 与 modifySlice 共享底层数组,所以 0 号位置 被修改为哦 1024 但长度信息没有被修改
所以只显示 1024 1 2
建议看看 slice 底层实现
RoninZc
2022-08-24 10:42:47 +08:00
修改一下

在 s= append(s, 2048) 执行后 s 被重新赋值 p 内数据为 0, 1, 2, 2048 ,len 为 4
tianyou666shen
2022-08-24 10:54:25 +08:00
楼上说的对的 主要就是两点
1.go 里面的赋值是复制一份变量
2.slice 底层数组相同时,修改值会影响所有引用此数组的切片数据

main 函数中的 slice,长度是 3,开始是[0,1,2]
modify 修改时,用相同底层数组复制了一份 slice,然后新的 slice append 后长度变为 3+1=4,随后修改 0 索引的底层数组值,此时底层数组为[1024,1,2,2048]
然后返回 main,此时长度还是 3,所以仅能够访问底层数组的前三个位置,打印显示[1024,1,2],如果要显示后面的 2048,需要将 slice 的长度+1
RoninZc
2022-08-24 10:59:09 +08:00
还有,上述示例中未考虑到 modifySlice 执行过程中 slice 扩容的情况
如果发生扩容 其后的修改都将指向的是新创建的 slice ,对 main 函数中的 slice 将毫无影响
所以一般这种情况推荐 modifySlice 函数中将 slice 返回,在 main 中重新赋值
```
func main() {
var s []int
for i := 0; i < 3; i++ {
s = append(s, i)
}

s = modifySlice(s)

fmt.Println(s)
}

func modifySlice(s []int) []int {
s = append(s, 2048)
s[0] = 1024
return s
}
```
fiypig
2022-08-24 11:01:05 +08:00
return s 就是你要的效果了
rimutuyuan
2022-08-24 11:03:49 +08:00
感谢各位大佬
kkeep
2022-08-24 11:52:19 +08:00
你多看看 a tour of go 即可
Erroad
2022-08-24 11:58:21 +08:00
GP1
2022-08-24 12:04:33 +08:00
你修改之后倒是 return 回去啊?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/874984

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX