又掉进slice切片的坑里面了


本文摘自网络,作者TonoT,侵删。

最近在写一个函数时遇到了一个不知名的错误,排查了很久才发现了问题,这里做个笔记,下面以简短的代码复现一个这个问题

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的结构体表示

// 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不同的原因

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的时候)对切片的修改也会造成对数组的修改,其他建立在此数组之上的切片的值也会发生变化

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也会造成底层数组的变化

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]
}

千防万防还是掉坑里面了。


相关阅读 >>

Golang可以写网站吗

Go-zero 是如何追踪你的请求链路?

关于Golang当中对select的理解

聊一聊Golang的协程

Go中sync.mutex源码解读

visdom: rust版使用类jquery api的html解析操作库

Go modules使用详解

rtmp协议视频平台easydss编译过程中Go语言异步信息处理设计与实现

如何处理Golang返回值较多问题

Golang判断数据类型和获取数据类型

更多相关阅读请进入《Go》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...