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

 更新时间:2025年11月02日 09:45:55   作者:学亮编程手记  
这篇文章主要介绍了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指针指向这里
  • len(slice):切片包含了 arr[1], arr[2], arr[3] 这三个元素,所以 长度为 3。
  • cap(slice):切片的指针从 arr[1] 开始,底层数组的末尾是 arr[4],所以从起始位置到末尾有 arr[1], arr[2], arr[3], arr[4] 这 4个位置,因此 容量为 4。
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 操作变化在触发扩容前不变
用途决定可访问的元素范围影响性能(减少内存分配和复制)
  • 切片是引用类型。多个切片可以共享同一个底层数组。修改一个切片的元素可能会影响其他共享底层数组的切片。
  • “扩容”是一个相对昂贵的操作,涉及内存分配和数据复制。在能预估所需数据量的情况下,使用 make([]T, 0, capacity) 预先分配一个足够大的容量是提升性能的有效手段。
  • 对切片进行重新切片(reslicing,如 s2 := s1[1:3])操作时,新切片会和原切片共享底层数组。新切片的长度和容量会基于新的起始索引重新计算。

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

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

相关文章

  • Go语言上下文context底层原理

    Go语言上下文context底层原理

    这篇文章主要介绍了Go语言上下文context底层原理,context是Go中用来进程通信的一种方式,其底层是借助channl与snyc.Mutex实现的,更多相关内容需要的小伙伴可以参加一下
    2022-06-06
  • Golang 并发的实现

    Golang 并发的实现

    本文主要介绍了Golang 并发的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-05-05
  • 基于Go语言实现Base62编码的三种方式以及对比分析

    基于Go语言实现Base62编码的三种方式以及对比分析

    Base62 编码是一种在字符编码中使用62个字符的编码方式,在计算机科学中,,Go语言是一种静态类型、编译型语言,它由Google开发并开源,本文给大家介绍了Go语言实现Base62编码的三种方式以及对比分析,需要的朋友可以参考下
    2025-05-05
  • Go语言做爬虫状态码返回418的问题解决

    Go语言做爬虫状态码返回418的问题解决

    在使用Go语言做爬虫时,使用http.Get(url)去获取网页内容,状态码返回404,本文我们就详细的介绍一下解决方法,感兴趣的可以了解一下
    2021-12-12
  • 一百行Golang代码实现简单并发聊天室

    一百行Golang代码实现简单并发聊天室

    这篇文章主要为大家详细介绍了一百行Golang代码如何实现简单并发聊天室,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-08-08
  • 谈论Go 什么时候会触发 GC问题

    谈论Go 什么时候会触发 GC问题

    Go 语言作为一门新语言,在早期经常遭到唾弃的就是在垃圾回收(下称:GC)机制中 STW(Stop-The-World)的时间过长。下面文章就对此话题展开,感兴趣的小伙伴可以参考下面文章的内容
    2021-09-09
  • Golang实现Redis事务深入探究

    Golang实现Redis事务深入探究

    这篇文章主要介绍了Golang实现Redis事务深入探究,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • 聊聊Golang的语言结构和变量问题

    聊聊Golang的语言结构和变量问题

    这篇文章主要介绍了Golang的语言结构和变量问题,在golang中定义变量的一般形式是使用 var 关键字,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2021-11-11
  • Go设计模式之迭代器模式讲解和代码示例

    Go设计模式之迭代器模式讲解和代码示例

    迭代器是一种行为设计模式, 让你能在不暴露复杂数据结构内部细节的情况下遍历其中所有的元素,本文将为大家详细介绍Go 迭代器模式,文中详细的代码示例,需要的朋友可以参考下
    2023-07-07
  • go面向对象方式操作JSON库实现四则运算

    go面向对象方式操作JSON库实现四则运算

    这篇文章主要为大家介绍了go面向对象方式操作JSON库实现四则运算的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07

最新评论