Go 中切片(Slice)的长度与容量

切片长度与容量在 Go 中很常见。切片长度是切片中可用元素的数量,而切片容量是从切片中第一个元素开始计算的底层数组中的元素数量。
Go 中的开发者经常混淆切片长度和容量,或者对它们不够了解。理解这两个概念对于高效处理切片的核心操作,比如切片的初始化、使用 append 添加元素、复制或切片操作等,至关重要。对这些概念的误解可能导致切片的不合理使用,甚至造成内存泄漏。
在 Go 中,切片是由数组支持的。这意味着切片的数据以连续的方式存储在数组数据结构中。切片还负责在底层数组已满时添加元素,或在几乎为空时缩减底层数组。
在内部,切片包含指向底层数组的指针,以及长度和容量。长度表示切片包含的元素数量,而容量表示底层数组中的元素数量,从切片中的第一个元素开始计算。让我们通过一些示例来更清楚地了解这些概念。首先,让我们使用给定的长度和容量初始化一个切片:
s := make([]int, 3, 6) // Three-length, six-capacity slice
第一个参数,表示长度,是必须的。但是,第二个参数表示容量是可选的。图1展示了此代码在内存中的结果。

Figure 1 — 一个长度为3、容量为6的切片
在这种情况下,make 创建了一个包含六个元素的数组(容量)。但由于长度设置为3,Go 只初始化了前三个元素。另外,因为切片是 []int 类型,所以前三个元素被初始化为 int 类型的零值:0。灰色元素已经分配但尚未使用。
如果我们打印这个切片,会得到长度范围内的元素 [0 0 0]。如果我们将 s[1] 设为1,切片的第二个元素会更新,但不会影响其长度或容量。图2说明了这一点。

图2 — 更新切片的第二个元素:s[1] = 1
然而,访问超出长度范围之外的元素是被禁止的,即使它在内存中已经分配。例如,s[4] = 0 会导致以下 panic:
panic: runtime error: index out of range [4] with length 3
我们如何使用切片剩余的空间呢?通过使用内置函数 append:
s = append(s, 2)
这段代码向现有的 s 切片追加了一个新元素。它使用了第一个灰色元素(已分配但尚未使用)来存储元素2,正如图3所示。

图3 — 向 s 切片追加一个元素
切片的长度从3更新为4,因为现在切片包含了四个元素。现在,如果我们再添加三个元素以至于后台数组不够大,会发生什么?
s = append(s, 3, 4, 5)
fmt.Println(s)
如果我们运行这段代码,会看到切片能够满足我们的请求:
[0 1 0 2 3 4 5]
因为数组是一个固定大小的结构,在第4个元素之前,它能够存储新的元素。当我们想要插入第5个元素时,数组已经满了:Go 内部会创建另一个数组,将所有元素复制过去,然后再插入第5个元素。图4展示了这个过程。

图4 — 因为初始的后台数组已满,Go 创建了另一个数组并复制了所有元素。
现在切片引用了新的后台数组。之前的后台数组会怎样呢?如果它不再被引用,它最终会被垃圾收集器(GC)释放,如果它是在堆上分配的话(我们在错误#95 “不理解堆栈与堆的区别”中讨论了堆内存,并在错误#99 “不理解GC的工作原理”中讨论了GC的工作原理)。
对切片进行切片操作会发生什么?切片是对数组或切片进行的操作,提供了一个左闭右开的范围;第一个索引是包括的,而第二个索引是排除的。以下示例展示了影响,并在图5中显示了内存中的结果:
s1 := make([]int, 3, 6) // Three-length, six-capacity slice
s2 := s1[1:3] // Slicing from indices 1 to 3

图5 — 切片 s1 和 s2 引用相同的后台数组,但长度和容量不同
首先,s1 是一个长度为3、容量为6的切片。当通过对 s1 进行切片创建 s2 时,两个切片都引用同一个后台数组。但是,s2 从不同的索引开始,即索引1。因此,它的长度和容量(长度为2,容量为5)与 s1 不同。如果我们更新 s1[1] 或 s2[0],则更改会作用于同一个数组,因此在两个切片中都是可见的,如图6所示。

图6 — 因为 s1 和 s2 共享同一个数组,更新共同的元素会使两个切片中的更改都可见
现在,如果我们向 s2 添加一个元素会发生什么?以下代码会同时改变 s1 吗?
s2 = append(s2, 2)
共享的后台数组被修改,但只有 s2 的长度发生了变化。图7展示了向 s2 添加元素的结果。

图7 — 向 s2 添加元素
s1 仍然是一个长度为3、容量为6的切片。因此,如果我们打印 s1 和 s2,添加的元素只会在 s2 中可见:
s1=[0 1 0], s2=[1 0 2]
很重要理解这种行为,这样我们在使用 append 时就不会形成错误的假设。
注意: 在这些示例中,后台数组是内部的,不直接对 Go 开发者可见。唯一的例外是从现有数组切片创建切片。
还有最后一件事需要注意:如果我们不断向 s2 中添加元素,直到后台数组满为止,内存状态会是怎样的?让我们再添加三个元素,以便后台数组没有足够的容量:
s2 = append(s2, 3)
s2 = append(s2, 4) // At this stage, the backing is already full
s2 = append(s2, 5)
这段代码导致创建了另一个后台数组。图 8 展示了内存中的结果。

图 8 — 向 s2 添加元素直到后台数组已满
s1 和 s2 现在引用两个不同的数组。由于 s1 仍然是一个三长度、六容量的切片,它仍然有一些可用缓冲区,因此它继续引用最初的数组。而且,新的后台数组是通过从 s2 的第一个索引复制初始数组而生成的。这就是为什么新数组从元素 1 开始,而不是 0。
结论
总结一下,切片长度 是切片中可用元素的数量,而 切片容量 是后台数组中的元素数量。向一个已满的切片(长度 == 容量)添加元素会导致创建一个新的后台数组,将之前数组中的所有元素复制到新数组中,并更新切片指向新数组。
相关文章:
Go 中切片(Slice)的长度与容量
切片长度与容量在 Go 中很常见。切片长度是切片中可用元素的数量,而切片容量是从切片中第一个元素开始计算的底层数组中的元素数量。 Go 中的开发者经常混淆切片长度和容量,或者对它们不够了解。理解这两个概念对于高效处理切片的核心操作,比…...
顶级大厂Quora如何优化数据库性能?
Quora 的流量涉及大量阅读而非写入,一直致力于优化读和数据量而非写。 0 数据库负载的主要部分 读取数据量写入 1 优化读取 1.1 不同类型的读需要不同优化 ① 复杂查询,如连接、聚合等 在查询计数已成为问题的情况下,它们在另一个表中构…...
Java第二十章多线程
一、线程简介 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一个进程可以包含多个线程,这些线程可以并发执行。线程拥有自己的栈和局部变量,但是它们共享进程的其他资源,如…...
家庭教育,培养娃什么最重要?
家庭教育,培养娃什么最重要? 培养能力最重要 (我这么认为的) 时代巨变,技术变革的非常快,所以总的来说 年轻一代接触的新东西慢慢比老一代的要多,年轻一代的工作会比老一代的多而且多很多&…...
Linux 进程(一)
1 操作系统 概念:任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括 内核(进程管理,内存管理,文件管理,驱动管理) 其他程序(例…...
vue中的keep-alive详解与应用场景
🌈个人主页:前端青山 🔥系列专栏:Vue篇 🔖人终将被年少不可得之物困其一生 依旧青山,本期给大家带来vue篇专栏内容:vue-keep-alive 目录 一、Keep-alive 是什么 二、使用场景 三、原理分析 四、案例实现 activa…...
软件设计师——程序设计语言基础(一)
📑前言 本文主要是【程序设计语言基础】——程序设计语言基础的相关题目,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是听风与他🥇 ☁️博客首页:CSDN主页听风与他 &#…...
Apache简介与安装
先导概念: 静态网站: 最早的建站方式,每个页面都是一个独立的文件,需要手动上传或编辑。网页内容固定不变。例如,个人博客、静态企业官网等。 动态网站: 网站内容可根据不同情况动态变更,一般通过数据库进行架构。包含服务器端脚本,可以实现更丰富的功能。例如,社…...
set与map
set与map 一、序列式容器与关联式容器二、pair1、键值对2、作用3、构造函数4、make_pair(1)构造函数(2)作用 5、代码6、运行结果 三、set1、概念2、代码3、运行结果4、说明 四、multiset1、与set的关系2、代码3、运行结果 五、map…...
基于单片机智能液位水位监测控制系统
**单片机设计介绍, 基于单片机智能液位水位监测控制系统 文章目录 一 概要特点应用场景工作原理实现方式 系统功能实时监测控制调节报警功能数据记录与分析 总结 二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 ## 系统介绍 基于单片机…...
C#,《小白学程序》第十七课:随机数(Random)第四,移动平均值(Moving Average)的计算方法与代码
1 文本格式 /// <summary> /// 《小白学程序》第十七课:随机数(Random)第四,移动平均值的计算方法与代码 /// 继续学习数据统计,移动平均值的计算方法 /// 移动平均值就是一定步长内数值的平均值,用…...
行情分析——加密货币市场大盘走势(11.29)
大饼已经形成了底背离,即MACD往下走,而价格还在往上走,这种后续往往会大跌。继续把空单拿好,已经持仓的无需加仓。多次上涨却一直不能突破,说明多空和空军力量都很强,等待后续出方向。在笔者看来࿰…...
C++——string的字符串比较,字符存取,插入和删除和子串
一. string字符串比较 功能描述:字符串之间的比较 比较方式:字符串比较是按字符的ASCII码进行对比 返回 0 > 返回 1 < 返回 -1 函数原型: *int compare(const string &s) const; //与字符串s比较 *int compare(const char *s) const; //…...
字节10年经验之谈 —— 从0到1开发自动化测试框架!
一、序言 随着项目版本的快速迭代、APP测试有以下几个特点: 首先,功能点多且细,测试工作量大,容易遗漏;其次,代码模块常改动,回归测试很频繁,测试重复低效;最后&#x…...
Mysql(基本介绍+下载安装+服务器+基本使用+建库建表+navicat/mybitas工具+外键及实例)
一、Mysql基本介绍 当谈论MySQL时,通常指的是一个流行的开源关系型数据库管理系统(RDBMS)。MySQL是由瑞典的开发者在1995年创建的,后来被Sun Microsystems收购,最终成为Oracle Corporation的一部分。以下是关于MySQL的…...
Python+requests+Jenkins接口自动化测试实例
在做功能测试的基础上,我平时也会用postman测试接口,不过postman只能测试一个一个接口,不能连贯起来,特别是我们公司的接口很多都是要用到token的,导致我每次测个需要登录的接口都要去获取到token,做了很多…...
SpringBoot3核心原理
SpringBoot3核心原理 事件和监听器 生命周期监听 场景:监听应用的生命周期 可以通过下面步骤自定义SpringApplicationRunListener来监听事件。 ①、编写SpringApplicationRunListener实现类 ②、在META-INF/spring.factories中配置org.springframework.boot.Sprin…...
JS常用数据类型转换(数字型和字符串型之间转换)
提供了5中基本数据类型:数字 number 字符串 string 布尔 boolean 空值 null 未定义的 undefined 常用的是数字型和字符串型之间的转换,常用的转换方法如下: 1 数字型转换成字符串型 a) 使用String()方法…...
算法通关村第一关—青铜挑战—用Java基本实现各种链表操作
文章目录 第一关—链表【青铜挑战】1.1 单链表的概念1.2 链表的相关概念1.3 创建链表 - Java实现1.4 链表的增删改查1.4.1 遍历单链表 - 求单链表长度1.4.2 链表插入 - 三种位置插入(1)在链表的表头插入(2)在链表的中间插入&#…...
SparkRDD及算子-python版
RDD相关知识 RDD介绍 RDD 是Spark的核心抽象,即 弹性分布式数据集(residenta distributed dataset)。代表一个不可变,可分区,里面元素可并行计算的集合。其具有数据流模型的特点:自动容错,位置…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...
