一篇文章搞懂Go语言切片底层原理(图文并茂+举例讲解)

1. 切片和数组的底层关系

Go语言切片的数据结构是一个结构体:

type slice struct {array unsafe.Pointerlen   intcap   int
}

Go语言中切片的内部结构包含地址、大小和容量。将数组比喻成一个蛋糕,那么切片就是需要切的那一块,而那一块的的大小就是切片的大小,而容量可以理解为装这一块蛋糕的袋子的大小。通过切片,我们可以快速地对数组进行操作。

从数组或切片中获取新切片

从数组中获取新切片,代码如下:
var a  = [3]int{1, 2, 3}
fmt.Println(a, a[1:2])

a是一个被初始化为长度为3,值为{1,2,3}的一维数组。使用a[1:2]可以生成一个新的切片:

[1 2 3]  [2]
从数组中获取原切片,代码如下:
a := []int{1, 2, 3}
fmt.Println(a[:])

对a使用a[:]操作后,生成的切片与原数组内容一致。

清空切片
a := []int{1, 2, 3}
fmt.Println(a[0:0])

对a使用a[0:0]操作后,切片大小为0,相当于清空了切片。

综上,我们发现获取切片,实际上是对底层数组的某一片段拿出来进行操作。非常类似于C语言的指针,可以通过指针运算,来达到类似切片的目的,但是存在野指针的风险。
而切片在指针的基础上增加了大小,使用中不允许对切片的内部地址和大小进行手动调整。因此比指针更加安全、更加强大。

简单来说,切片在内部对指针进行了限制和管理,从而实现更加安全且快速地对数据集合进行操作。

2. 切片的扩容机制

使用make函数构造切片

若需要动态地构建一个切片,则需要使用make函数:

make( []Type, size, cap )

size指这个切片的实际大小;cap指的是预分配的内存空间大小。
make函数构造切片的过程中是一定进行了内存分配的操作

扩容

当对切片进行动态地添加元素时,若切片大小超出容量,容量会以2的倍数进行扩容。
我们看这样一个案例:

silce := make([]int, 0)for i := 0; i < 10; i++ {silce = append(silce, i+1)fmt.Printf("len:%d cap:%d p:%p\n", len(silce), cap(silce), silce)}

可以发现:切片的大小和容量的关系只有在切片的大小超过切片的容量时,才会触发切片容量的扩容,且每次扩容都是2倍扩容。

len:1 cap:1 p:0xc00000a0c8
len:2 cap:2 p:0xc00000a110
len:3 cap:4 p:0xc000012220
len:4 cap:4 p:0xc000012220
len:5 cap:8 p:0xc0000183c0
len:6 cap:8 p:0xc0000183c0
len:7 cap:8 p:0xc0000183c0
len:8 cap:8 p:0xc0000183c0
len:9 cap:16 p:0xc000100080
len:10 cap:16 p:0xc000100080

观察每次扩容,切片的地址都会进行改变,这是为什么呢?

我们在上文讲"切片与数组"的关系时,分析过:切片的本质是一种"安全的指针"。而底层数组的内存大小被分配结束后是无法进行扩容的(本质上是顺序表)。因此,若要进行扩容,那么只能创建一个新的数组(Go内部规定容量为原先的2倍),然后将原数组的数据转移到新数组内,并让切片的指针重新指向新的数组。

因此,每次扩容都会进行一次“搬家”,而搬家后,家的指针自然要改变到新家。

未完待续

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

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

相关文章

c++学生管理系统

想要实现的功能 1&#xff0c;可以增加学生的信息&#xff0c;包括&#xff08;姓名&#xff0c;学号,c成绩&#xff0c;高数成绩&#xff0c;英语成绩&#xff09; 2&#xff0c;可以删除学生信息 3&#xff0c;修改学生信息 4&#xff0c;显示所有学生信息 5&#xff0c…

支持AMD GPU的llm.c

anthonix/llm.c: LLM training in simple, raw C/HIP for AMD GPUs (github.com) llm.c for AMD devices This is a fork of Andrej Karpathys llm.c with support for AMD devices. 性能 在单个7900 XTX显卡上使用默认设置&#xff0c;目前的训练步骤耗时约为79毫秒&#x…

Docker的安装、启动和配置镜像加速

前言&#xff1a; Docker 分为 CE 和 EE 两大版本。CE 即社区版&#xff08;免费&#xff0c;支持周期 7 个月&#xff09;&#xff0c;EE 即企业版&#xff0c;强调安全&#xff0c;付费使用&#xff0c;支持周期 24 个月。 而企业部署一般都是采用Linux操作系统&#xff0c;而…

【软件设计师】2022年上半年真题解析

​​冯诺依曼计算机体系结构的基本特点是&#xff1a; A. 程序指令和数据都采用二进制表示 - 这是正确的&#xff0c;因为冯诺依曼架构下的计算机使用二进制形式来表示和处理所有信息&#xff0c;包括指令和数据。 B. 程序指令总是存储在主存中&#xff0c;而数据则存储在高速…

Java基础语法详解——入门学习教程

Java 基础 目录 一、数据类型 基本类型包装类型缓存池 二、String 概览不可变的好处String, StringBuffer and StringBuilder String Poolnew String(“abc”) 三、运算 参数传递float 与 double隐式类型转换switch 四、关键字 finalstatic 五、Object 通用方法 概览equals()ha…

深入解析 MongoDB Map-Reduce:强大数据聚合与分析的利器

Map-Reduce 是一种用于处理和生成大数据集的方法&#xff0c;MongoDB 支持 Map-Reduce 操作以执行复杂的数据聚合任务。Map-Reduce 操作由两个阶段组成&#xff1a;Map 阶段和 Reduce 阶段。 基本语法 在 MongoDB 中&#xff0c;可以使用 db.collection.mapReduce() 方法执行…

IsoBench:多模态基础模型性能的基准测试与优化

随着多模态基础模型的快速发展&#xff0c;如何准确评估这些模型在不同输入模态下的性能成为了一个重要课题。本文提出了IsoBench&#xff0c;一个基准数据集&#xff0c;旨在通过提供多种同构&#xff08;isomorphic&#xff09;表示形式的问题&#xff0c;来测试和评估多模态…

算法(十三)回溯算法---N皇后问题

文章目录 算法概念经典例子 - N皇后问题什么是N皇后问题&#xff1f;实现思路 算法概念 回溯算法是类似枚举的深度优先搜索尝试过程&#xff0c;主要是再搜索尝试中寻找问题的解&#xff0c;当发生不满足求解条件时&#xff0c;就会”回溯“返回&#xff08;也就是递归返回&am…

enum4linux一键查询SMB信息(KALI工具系列十六)

目录 1、KALI LINUX简介 2、enum4linux工具简介 3、在KALI中使用enum4linux 3.1 目标主机IP&#xff08;win&#xff09; ​编辑 3.2 KALI的IP 4、操作示例 4.1 运行工具 4.2 列出用户名 4.3 提取用户名 4.4 使用自定义RID范围 4.5 列出组 4.6 列出共享文件夹 4.7…

【笔记小记】掌握市场脉动:全营销解决方案的力量

前面虽然说了这个模型&#xff0c;而且是分章说的&#xff0c;那么在此以笔记小记的形式再说一下&#xff0c;企业面临的挑战与日俱增&#xff0c;消费者需求的多样化、技术的不断进步、全球化的深入以及社会责任的日益重要&#xff0c;这些因素共同塑造了市场的现状和未来&…

网络监听技术

网络监听技术 网络监听概述网络监听环境 流量劫持网络环境共享式网络监听原理交换式网络监听交换机的工作方式交换网络监听&#xff1a;交换机集线器交换网络监听&#xff1a;端口镜像交换网络监听&#xff1a;MAC洪泛交换网络监听&#xff1a;MAC洪泛交换网络监听&#xff1a;…

【Unix】消息类的格式与使用

本文给出一个MacOS操作系统中的消息类的使用过程示例&#xff08;结合gencat命令&#xff0c;<nl_types.h>头文件以及catopen,catgets,catclose3个函数&#xff09; 首先根据对应的操作系统&#xff0c;查看gencat命令 man gencat 可以详细看到其中对于输入文件&#x…

Typescript高级: 深入理解extends keyof语法

概述 在TypeScript中&#xff0c;extends关键字是类型系统中一个极其重要的组成部分它不仅用于类的继承&#xff0c;也是类型兼容性检查和泛型约束的关键机制特别是当它与keyof关键字结合&#xff0c;形成K extends keyof T的结构时它为类型系统带来了强大的灵活性和表达能力&…

动态SQL where, choose语句

where语句就一个<where>标签, 很简单, 不再过多赘述 接下来我们来看 choose语句的使用 其实choose语句就像java里的swith语句 , 如果语句前面的生效 , 后面的就不会生效了 可以定义查询的优先级

读人工智能时代与人类未来笔记19_读后总结与感想兼导读

1. 基本信息 人工智能时代与人类未来 (美)亨利基辛格,(美)埃里克施密特,(美)丹尼尔胡滕洛赫尔 著 中信出版社,2023年6月出版 1.1. 读薄率 书籍总字数145千字&#xff0c;笔记总字数39934字。 读薄率39934145000≈27.5% 1.2. 读厚方向 千脑智能 脑机穿越 未来呼啸而来 …

【工具】 MyBatis Plus的SQL拦截器自动翻译替换“?“符号为真实数值

【工具】 MyBatis Plus的SQL拦截器自动翻译替换"?"符号为真实数值 使用MyBatis的配置如下所示&#xff1a; mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl调用接口&#xff0c;sql日志打印如下&#xff1a; 参数和sql语句不…

Spring Boot配置MySQL数据库连接数

1.如何在Spring Boot中配置MySQL数据库的连接数 1.1主要配置 在Spring Boot中配置MySQL数据库连接数通常涉及到两个主要的配置&#xff1a; &#xff08;1&#xff09;数据源配置&#xff1a;这通常是在application.properties或application.yml文件中完成的&#xff0c;用于…

顶底背离的终极猜想和运用

这几天圈内都在传底蓓离什么的。作为严肃的量化自媒体&#xff0c;我们就不跟着吃这波瓜了。不过&#xff0c;我一直很关注技术指标的顶背离和底背离&#xff0c;一直在追问它的成因如何&#xff0c;以及如何预测。 底蓓离把我目光再次吸引到这个领域来&#xff0c;于是突然有…

Java如何实现二维数组行列转换

二维数组行列转换就是行号和列号互换 public class Erweishuzubianli {public static void main(String[] args) {int array[][]new int[][]{{8,75,23},{21,55,34},{15,23,20}};int temp;for(int i0;i<array.length;i){for(int j0;j<array[i].length;j){temparray[i][j]…

LitCTF 2024(公开赛道)——WP

目录 Misc 涐贪恋和伱、甾―⑺d毎兮毎秒 你说得对&#xff0c;但__ 盯帧珍珠 Everywhere We Go 关键&#xff0c;太关键了! 女装照流量 原铁&#xff0c;启动&#xff01; 舔到最后应有尽有 The love Web exx 一个....池子&#xff1f; SAS - Serializing Authent…