又掉进slice切片的坑里面了

TonoT · · 689 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

最近在写一个函数时遇到了一个不知名的错误,排查了很久才发现了问题,这里做个笔记,下面以简短的代码复现一个这个问题 ```go func main() { s := [5]int{1, 2, 3, 4, 5} s1 := s[1:3] s2 := s[2:5] fmt.Println(s1,s2)//[2 3] [3 4 5] s1=append(s1,9) fmt.Println(s1,s2)//? } ``` 当slice1在append一个元素后对s2是否有影响?slice与数组的关系就不多说了,可以直接看一下slice的结构体表示 ```go // SliceHeader is the runtime representation of a slice. // It cannot be used safely or portably and its representation may // change in a later release. // Moreover, the Data field is not sufficient to guarantee the data // it references will not be garbage collected, so programs must keep // a separate, correctly typed pointer to the underlying data. type SliceHeader struct { Data uintptr Len int Cap int } ``` SliceHeader包含了三个元素: **1、一个指向数组中切片指定的开始位置;** **2、长度,即切片的长度,通过内置函数len获得;** **3、最大长度,即切片的最大容量,通过内置函数cap获得。** 在进行切片的划分的时候会根据当前已经选择的元素的大小作为len和整个数组的长度-起始位置作为cap。这就是下面cap不同的原因 ```go func main() { s := [5]int{1, 2, 3, 4, 5} s1 := s[1:3] s2 := s[2:4] fmt.Println(s1, len(s1), cap(s1))//[2 3] 2 4 fmt.Println(s2, len(s2), cap(s2))//[3 4] 2 3 } ``` 而这边需要注意的是,**在slice没有扩充(len小于cap的时候)对切片的修改也会造成对数组的修改,其他建立在此数组之上的切片的值也会发生变化** ```go func main() { s := [5]int{1, 2, 3, 4, 5} s1 := s[1:3] s2 := s[2:4] fmt.Println(s1,s2,s)//[2 3] [3 4] [1 2 3 4 5] s2[0]=0 fmt.Println(s1,s2,s)//[2 0] [0 4] [1 2 0 4 5] } ``` 不仅仅是直接通过索引下标复制会进行修改,**append也会造成底层数组的变化** ```go func main() { s := [5]int{1, 2, 3, 4, 5} s1 := s[1:3] s2 := s[2:5] fmt.Println(s1,s2)//[2 3] [3 4 5] s1=append(s1,9) fmt.Println(s1,s2)//[2 3 9] [3 9 5] } ``` 千防万防还是掉坑里面了。

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

689 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传