关于go:go-的-slice-底层的-陷阱

数组是一片间断的内存。slice 则是一个构造体,蕴含三个字段:长度 len容量 cap底层数组

// runtime/slice.go
type slice struct {
    array unsafe.Pointer // 元素指针
    len   int // 长度 
    cap   int // 容量
}

slice 的生命周期围绕着按 cap 事后调配 底层数组cap 有余时重新分配 cap*2底层数组

特地要留神的时,当咱们应用下标范畴来失去 子切片 时,子切片父切片 指向的 底层数组 在此时是 同一片内存地址。后续 子切片 可能会因为 容量cap 有余而从新申请容量时,从 父切片底层数组 中独立进去。

package main

import (
    "fmt"
)

func main() {
    slice := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    s1 := slice[2:5] //len3 cap8
    s2 := s1[2:6:7]  //len4 cap5

    fmt.Println(s1, len(s1), cap(s1))
    fmt.Println(s2, len(s2), cap(s2))
    fmt.Println(strings.Repeat("=", 10))

    //s2的容量已满 如果后续再追加成员,将重新分配一套底层数组
    s2 = append(s2, 100)
    //s1和s2还在专用一套底层数组 s1[2] == s2[0]
    s1[2] = 20
    fmt.Println(s1, len(s1), cap(s1))
    fmt.Println(s2, len(s2), cap(s2))
    fmt.Println(strings.Repeat("=", 10))

    //s2的重新分配底层数组 容量裁减为原来的2倍=5*2
    s2 = append(s2, 200)
    //s1与s2的底层数组已不同 s1[2] 已无奈影响 s2[0]
    s1[2] = 200
    fmt.Println(s1, len(s1), cap(s1))
    fmt.Println(s2, len(s2), cap(s2))
}

只有当子切片的 容量cap 有余,从新申请调配新的容量内存段时,才会从父切片的底层数组中独立查出来。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理