go中长度len和容量cap的定义,如何计算,他们的关系是怎样的,底层是如何表示的

news/2025/2/24 15:31:14/文章来源:https://www.cnblogs.com/maidongdong/p/18734178

在 Go 语言中,len(长度)和 cap(容量)是与切片(slice)密切相关的两个概念,尤其是在处理动态数组时。让我详细解释它们的定义、计算方式、关系以及底层的实现。

1. 定义

  • 长度(len):表示切片当前包含的元素个数,也就是你实际可以访问的元素数量。
  • 容量(cap):表示切片从其第一个元素开始到底层数组末尾的最大可能元素个数,也就是切片当前能扩展到的最大长度(无需重新分配内存)。

简单来说,len 是“已用空间”,cap 是“可用空间”。

2. 如何计算

  • len:通过内置函数 len(slice) 获取,直接返回切片中当前元素的数量。
  • cap:通过内置函数 cap(slice) 获取,返回从切片的起始位置到底层数组末尾的元素总数。
  • 切片表达式:当你用 arr[i:j:k] 创建切片时:
    • len = j - i(切片中实际包含的元素数)。
    • cap = k - i(从起始位置到指定容量上限的元素数,如果省略 k,则 cap = 底层数组长度 - i)。

例如:

arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:3] // 从索引1到3(不包含3)
fmt.Println(len(slice)) // 输出 2 (元素: 2, 3)
fmt.Println(cap(slice)) // 输出 4 (从索引1到数组末尾: 2, 3, 4, 5)

3. 关系

  • lencap 的关系

    • len 始终小于或等于 caplen(slice) <= cap(slice)
    • len 等于 cap 时,切片已用尽其容量,若再追加元素(如用 append),会触发底层数组的重新分配,容量通常会加倍(具体取决于实现和当前容量大小)。
    • 通过切片操作,可以改变 lencap,但不能直接修改底层数组的元素个数。
  • 动态调整

    • append 添加元素时,如果 len < cap,切片会直接利用剩余容量,len 增加,cap 不变。
    • 如果 len == cap,Go 会分配一个更大的底层数组(通常是当前容量的两倍),将数据复制过去,cap 变为新数组的长度,len 则增加 1。

例如:

slice := []int{1, 2, 3} // len=3, cap=3
slice = append(slice, 4) // len=4, cap=6(容量翻倍)

4. 底层表示

在 Go 的运行时,切片是一个结构体,定义在 reflect.SliceHeader 中(源码层面),包含三个字段:

  • Data:指向底层数组的指针,表示数据的起始位置。
  • Len:长度,存储当前切片中的元素个数(int 类型)。
  • Cap:容量,存储从 Data 指向的位置到底层数组末尾的元素总数(int 类型)。

底层源码大致如下(伪代码形式):

type SliceHeader struct {Data uintptr // 指向底层数组的指针Len  int     // 长度Cap  int     // 容量
}

当你创建一个切片时,例如 slice := arr[1:3]

  • Data 指向 arr 的第 1 个元素。
  • Len 设置为 2(从索引 1 到 3 的元素个数)。
  • Cap 设置为 4(从索引 1 到数组末尾的元素个数)。

当使用 append 超出容量时,Go 会:

  1. 分配一个新的、更大的底层数组。
  2. 将旧数组的数据复制到新数组。
  3. 更新 Data 指向新数组,调整 LenCap

5. 示例与直观理解

arr := [6]int{0, 1, 2, 3, 4, 5}
slice := arr[2:4] // 切片包含 2, 3
fmt.Println(len(slice), cap(slice)) // 输出: 2 4
slice = append(slice, 99)           // len=3, cap=4(还有空间)
fmt.Println(len(slice), cap(slice)) // 输出: 3 4
slice = append(slice, 100)          // len=4, cap=4(满了)
slice = append(slice, 101)          // len=5, cap=8(重新分配,容量翻倍)
fmt.Println(len(slice), cap(slice)) // 输出: 5 8

总结

  • len 是当前元素数,cap 是潜在最大元素数。
  • len 可变但不超过 capcap 由底层数组和起始位置决定。
  • 底层通过 SliceHeader 结构体管理,动态扩展时会重新分配内存。

希望这个解释清晰明了!如果还有疑问,欢迎继续问我。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/889049.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

优化性能钩子useMemo

执行顺序 useMemo 是同步执行,而 useEffect 是异步的。 import { useMemo, useState, useEffect } from react;function TestComponent() {const [count, setCount] = useState(0);console.log(普通代码:在渲染期间同步执行);useMemo(() => {console.log(useMemo:在渲染期…

BUUCTF-Web方向21-25wp

[HCTF 2018]admin 打开环境,有三处提示,一个跳转链接,一个登录注册,一个提示不是admin点击hctf,无法访问注册个账号,依旧无法查看,看来需要admin账号弱口令 爆破密码当密码未123长度明显不同登录session伪造 在修改密码界面,提示session下载该源码查看,index.php {% i…

useMemo 与 useEffect

执行顺序 useMemo 是同步执行,而 useEffect 是异步的。 import { useMemo, useState, useEffect } from react;function TestComponent() {const [count, setCount] = useState(0);console.log(普通代码:在渲染期间同步执行);useMemo(() => {console.log(useMemo:在渲染期…

测试用例管理工具2

一、bug的等级 (1)1级bug (致命bug) (2)2级bug(严重bug) (3)3级bug(一般bug) (4)4级bug(简易性bug)- 划分- 1级bug (致命bug):必须优先修改,在测试中较少出现,一旦出现应立即中止当前版本测试; 致命bug: (1)常规操作引起的崩溃,死机,死循环,内存泄…

FPGA Assembly

FASM 是一种文件格式,用于指定 FPGA 比特流中需要置1或清0的位。FASM 的设计初衷是提供一个中间层,令 FPGA 布局布线工具无需关心实际运行的 FPGA 比特流文件格式而工作。FASM 文件格式具有以下特性:从文件中删除任意一行都不会影响其有效性(注:这里的“有效性”指的是能正…

Flink 实战之维表关联

生产应用中,经常遇到将实时 **流式数据** 与 **维表数据** 进行关联的场景。常见的维表关联方式有多种,本文对以下 3 种进行了实现,并对每种方法的优缺点进行了比较:1. 预加载维表 2. 异步 IO 3. 广播维表下面分别使用不同方式来完成维表 join 的实验,附源码和实时动效。F…

Sa2VA环境搭建推理测试

引子 Sa2VA模型通过结合SAM-2和LLaVA,将文本、图像和视频统一到共享的LLM标记空间中,能够在少量指令微调下执行多种任务,如图像/视频对话、指称分割和字幕生成。该模型在视频编辑和内容创作中展现出强大的性能,在相关基准任务中达到了SOTA水平。OK,那就让我们开始吧。一、…

20-bluecms代码审计、thinkphp相关知识cve和cnvd编号申请

1、对bluecms进行代码审计,分析复现文件上传、ssti模板注入、文件删除等漏洞 文件上传审计admin/tpl_manage.php 文件发现,在do_edit模块有三个参数(act = do_edit、tpl_name = 写入文件名称、tpl_content = 写入内容,且代码中未对文件名过滤,导致可以上传任意文件。查看对…

ios SDK AB 开关切换

在数据库的这个服务器 然后再ctest1数据库新建编辑器然后查询select* fromapp_config ac whereaccess_no = 12100186 //这个是应用IDand module = abSwitchand param_name = export_otel_ab查到后,把param_value改为B,或者A,然后回车,然后点击图中的保存 保存后等两分钟,…

CS Course Learning

【李宏毅】2024大语言模型课程 课程学习课程链接:https://speech.ee.ntu.edu.tw/~hylee/genai/2024-spring.php Bilibili相关视频链接:https://www.bilibili.com/video/BV1XS411w7qrGPT: Autoregressive model In-context LearningChain of Thoughts (CoT) Tree of Thoughts …

跟着狂神学markdown作业01天

markdown学习 标题 一共可以做六级标题 格式为#+空格+标题 几级标题就打几个空格 字体 粗体:hello,world 两边各加两个*号 斜体:hello,world 两边各加一个*号 粗体+斜体:hello,world 两边各加三个***号 删除效果:hello,world 引用选择狂神说java,走向人生巅峰(用>…

java知识面试day4

1.常见的关键字有哪些static:静态变量,静态变量被所有对象共享,在内存中只有一个副本。具有静态变量,静态方法块,静态代码块(在类加载时候被指执行一次),静态内部类:非静态内部类需要依赖外部实列,但静态内部类不需要。final 基本数据类型用final修饰不能修改,引用对象被…