golang-切片

slice组成

slice由三个部分组成:指针、长度和容量

  1. 指针指向底层连续内存空间的起点
  2. 长度是slice中实际存放的元素的个数,可以通过下标访问
  3. 容量是为slice分配了足够存放n个元素的空间,在到达这个容量之前不需要扩容
type slice struct {
    array unsafe.Pointer // 指向底层数组的指针
    len   int            // 长度
    cap   int            // 容量
}

容量一定是大于等于长度的

通过slice的数据结构定义可以看到,在传递切片的时候,对slice进行了一次值拷贝。但是内部存放的地址是相同的,所以也相当于是引用传递

初始化方式

1. 直接声明

var s []int

此时s的值为nil,不能直接使用,需要先初始化
但是可以使用append函数

2. 使用make函数初始化

分为两种方式

  • 只指定长度
s := make([]int, 5)

长度一旦被指定,就代表对应的位置已经分配了元素(可以通过下标索引获取),默认为元素类型的零值
只指定长度时,默认容量和长度相等

  • 指定长度和容量
s := make([]int, 5, 10)

指定长度和容量时,长度必须小于等于容量

3. 使用字面量

s := []int{1, 2, 3}

使用字面量初始化时,长度和容量都由字面量决定
如上面的例子,长度为3,容量也为3

slice初始化流程

源码位于runtime/slice.go

func makeslice(et *_type, len, cap int) unsafe.Pointer {
    // 分配内存,关心的是cap
    // 根据类型大小和容量,计算需要分配的内存大小
    mem, overflow := math.MulUintptr(et.size, uintptr(cap))
    if overflow || mem > maxAlloc || len < 0 || len > cap {
        // 内存溢出或者分配的内存过大
        // 或者长度小于0或者长度大于容量
        // 都会报错
        panicmakeslicelen()
    }
    // 分配内存
    return mallocgc(mem, et, true)
}

slice的截取

s := []int{1, 2, 3, 4, 5}
s1 := s[1:3] // [2, 3] 左闭右开

截取时,会生成一个新的slice,但是底层数组还是原来的数组,所以修改s1也会影响s

如果截取的长度大于容量,会报错

posted @ 2025-05-05 20:45  yimina  阅读(38)  评论(0)    收藏  举报