Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > Golang 切片的长度和容量

Golang语言中切片的长度和容量的概念和使用

作者:学亮编程手记

这篇文章主要介绍了Golang语言中切片的长度和容量的概念和使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

本文我们来详细讲解 Go 语言中切片(Slice)的长度(Length)容量(Capacity)。这是理解切片工作原理的核心概念。

核心概念

  1. 长度(Length):

    • 表示切片当前实际包含的元素个数
    • 通过内置函数 len(slice) 获取。
    • 访问切片中索引 >= len(slice) 的元素会引发“索引越界”的运行时恐慌(panic)。
  2. 容量(Capacity):

    • 表示切片底层数组(Underlying Array)从切片的起始位置到数组末尾的元素个数
    • 它代表了切片在不分配新内存的情况下,可以增长的最大限度。
    • 通过内置函数 cap(slice) 获取。

底层数组(Underlying Array)

切片是一个轻量级的数据结构,它提供了对底层数组一个连续片段的引用。它包含三个组件:

这个概念是理解长度和容量区别的关键。

图示与示例

让我们通过一个例子和图示来理解。

// 1. 创建一个底层数组
arr := [5]int{10, 20, 30, 40, 50} // 数组,长度和容量固定为5

// 2. 基于数组创建一个切片
// slice 从 arr[1] 开始,到 arr[3] 结束 (不包括 arr[4])
slice := arr[1:4] // [20, 30, 40]

此时的内存布局可以这样表示:

底层数组: [10, 20, 30, 40, 50]
索引:      0   1   2   3   4
              ^         ^
              |         |
           slice起始   slice结束 (不包括索引4)
           slice指针指向这里
fmt.Println(slice)      // 输出: [20 30 40]
fmt.Println(len(slice)) // 输出: 3
fmt.Println(cap(slice)) // 输出: 4

容量是如何被使用的:append 函数

当你使用 append 函数向切片追加新元素时,Go 运行时会检查容量是否足够。

  1. 容量足够时
    新元素会被直接放入底层数组切片末尾之后的空间,长度增加,容量不变。

    newSlice := append(slice, 60) // 追加元素 60
    fmt.Println(newSlice)          // 输出: [20 30 40 60]
    fmt.Println(len(newSlice))     // 输出: 4
    fmt.Println(cap(newSlice))     // 输出: 4 (容量刚好够用,没有分配新数组)
    fmt.Println(arr)               // 输出: [10 20 30 40 60] (原数组被修改了!)
    
  2. 容量不足时
    Go 运行时会创建一个新的、更大的底层数组(通常是当前容量的 2 倍,但对于较小的切片,增长策略可能不同),将原有元素复制到新数组中,然后追加新元素。此时的切片引用的是一个全新的数组,与原数组无关

    newSlice2 := append(newSlice, 70, 80) // 追加两个元素,超出当前容量4
    fmt.Println(newSlice2)                 // 输出: [20 30 40 60 70 80]
    fmt.Println(len(newSlice2))            // 输出: 6
    fmt.Println(cap(newSlice2))            // 输出: 8 (新数组的容量,通常是旧容量的2倍)
    fmt.Println(arr)                       // 输出: [10 20 30 40 60] (原数组未受影响)
    

使用make创建切片时指定长度和容量

你可以使用 make 函数在创建切片时直接指定其初始长度和容量。

语法:make([]T, length, capacity)

// 创建一个切片,长度为3(前3个元素被初始化为零值),容量为5
s := make([]int, 3, 5)
fmt.Println(s)          // 输出: [0 0 0]
fmt.Println(len(s))     // 输出: 3
fmt.Println(cap(s))     // 输出: 5

// 你可以安全地访问和修改 s[0], s[1], s[2]
// 你可以追加最多2个新元素(5-3=2)而不会触发重新分配
s = append(s, 1)
fmt.Println(s)          // 输出: [0 0 0 1]
fmt.Println(len(s))     // 输出: 4

如果省略容量参数,则容量默认与长度相等。

s2 := make([]int, 3) // len=3, cap=3
fmt.Println(s2, len(s2), cap(s2)) // 输出: [0 0 0] 3 3

总结与要点

特性长度 (len)容量 (cap)
含义当前元素个数可增长的最大限度
函数len(s)cap(s)
动态性随 append/slice 操作变化在触发扩容前不变
用途决定可访问的元素范围影响性能(减少内存分配和复制)

理解长度和容量的区别,能帮助你更好地使用切片,写出更高效、更可靠的 Go 代码。

到此这篇关于Golang语言中切片的长度和容量的概念和使用的文章就介绍到这了,更多相关Golang 切片的长度和容量内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文