Go基础学习05-数组和切片关系深度解析

embedded/2024/9/29 23:31:51/

切片数组的联系

数组(array)和切片(slice)都属于集合类的类型,它们的值也都可以用来存储某一种类型的值(或者说元素)。数组切片最重要的不同在于:

  • 数组类型的值的长度是固定的,而切片类型的值的长度是可变长的。 数组的长度在声明它的时候就必须给定,并且在之后不会再改变。可以说,数组的长度是其类型的一部分。
  • 切片的类型字面量中只有其元素的类型,而没有其长度。切片的长度可以自动地随着其中元素数量的增长而增长,但不会随着元素数量的减少而减少。
  • 切片属于引用类型(切片、通道、函数),数组属于值类型(基础数据类型、结构体类型)。

数组切片的关系:

切片看作是对数组的一层简单的封装(在每个切片底层数据结构中,一定包含一个数组);
数组可以看作切片底层数据结构切片也可以看作是对数组的某个连续片段的引用。

切片的容量和长度的关系:

示例代码1:通过make初始化切片

	slice1 := make([]int, 5)slice2 := make([]int, 5, 8)fmt.Printf("slice1 len is : %d, cap is : %d\n", len(slice1), cap(slice1))fmt.Printf("slice2 len is : %d, cap is : %d\n", len(slice2), cap(slice2))

上述代码运行结果:

slice1 len is : 5, cap is : 5
slice2 len is : 5, cap is : 8

当我们使用make函数初始化切片时,如果不指明那个量,那么切片的容量就会和长度一致。如果使用make函数初始化切片时,指明了切片的容量,那么切片的容量就是此时指明的数据,不一定等于切片的长度。通过make函数初始化的切片,其容量代表了切片的底层数组的长度,上述的5和8代表底层数组的长度,数组的长度不可改变。 既然切片底层数据结构数组的长度不可改变,那么当切片容量不足时需要扩容时如果扩?正确的答案:切片容量不足时,会开辟一块更大的空间(足够存储扩容后的所有元素),随后将切片原有元素复制到新的空间,并将新添加的元素追加到后面,随后再将新的引用传递给切片

示例代码2:使用切片表达式基于某个数组切片生成新切片

 	slice3 := []int{1, 2, 3, 4, 5, 6, 7, 8}slice4 := slice3[3:6]fmt.Printf("slice3 elements is : %d\n", slice3)fmt.Printf("slice4 elements is : %d\n", slice4)fmt.Printf("slice3 len is : %d, cap is : %d\n", len(slice3), cap(slice3))fmt.Printf("slice4 len is : %d, cap is : %d\n", len(slice4), cap(slice4))

上述代码执行结果:

slice3 elements is : [1 2 3 4 5 6 7 8]
slice4 elements is : [4 5 6]
slice3 len is : 8, cap is : 8
slice4 len is : 3, cap is : 5

提醒读者特意关注一下第四行的输出结果,可以查看一下是否符合预期。
slice4 := slice3[3 : 6]表示透过切片能看到底层数据结构数组的数据范围,左开右闭。所以表示的就是slice3中元素的索引范围从3到5(不包含6),所以slice4此时输出的元素是456。
此时对于slice4的长度计算就是结束索引 - 起始索引:6-3=3。所以len(slice4)就是3。为什么cap(slice4) = 5,而不是3呢?

使用切片表达式基于数组或者切片生成新的切片,其本质和原数组或者旧切片共用相同的底层数据结构,可以将新切片看作在旧切片的基础上的一个封装,一个拥有左右边界的窗口,左边界是切片表达式的左值,右边界是切片表达式的右值(右边界不能大于原有切片的最大容量,否则panic)。slice4的底层数组就是slice3的底层数组,又因为,在底层数组不变的情况下,切片代表的窗口可以向右扩展,直至其底层数组的末尾。所以,slice4的容量就是其底层数组的长度8减去上述切片表达式中的那个起始索引3,即5。
切片代表的窗口是无法向左扩展的,也就是说,我们永远无法透过slice4看到slice3中最左边的那三个元素

如何估算切片容量的增长

一旦一个切片无法容纳更多的元素,Go 语言就会想办法扩容。但它并不会改变原来的切片,而是会生成一个容量更大的切片,然后将把原有的元素和新元素一并拷贝到新切片中。

  • 在一般的情况下,你可以简单地认为新切片的容量(以下简称新容量)将会是原切片容量(以下
    简称原容量)的 2 倍。
  • 但是,当原切片的长度(以下简称原长度)大于或等于1024时,Go 语言将会以原容量的1.25
    倍作为新容量的基准(以下新容量基准)。新容量基准会被调整(不断地与1.25相乘),直到结果不小于原长度与要追加的元素数量之和(以下简称新长度)。最终,新容量往往会比新长度大一些,当然,相等也是可能的。
  • 此外,如果我们一次追加的元素过多,以至于使新长度比原容量的 2 倍还要大,那么新容量就
    会以新长度为基准。

关于切片底层数组替换的思考

一个切片的底层数组永远不会被替换。虽然在扩容的时候 Go 语言一定会生成新的底层数组,但是它也同时生成了新的切片。它是把新的切片作为了新底层数组的窗口,而没有对原切片及其底层数组做任何改动。

  • 在无需扩容时,append函数返回的是指向原底层数组的新切片,而在需要扩容时,append函数返回的是指向新底层数组的新切片
  • 只要新长度不会超过切片的原容量,那么使用append函数对其追加元素的时候就不会引起扩容。这只会使紧邻切片窗口右边的(底层数组中的)元素被新的元素替换掉。
    代码示例:
	slice3 := []int{1, 2, 3, 4, 5, 6, 7, 8}slice4 := slice3[3:7]fmt.Printf("slice3 elements is : %d\n", slice3)fmt.Printf("slice4 elements is : %d\n", slice4)slice4 = append(slice4, 10)fmt.Printf("slice3 elements is : %d\n", slice3)fmt.Printf("slice4 elements is : %d\n", slice4)

运行结果:

slice3 elements is : [1 2 3 4 5 6 7 8]
slice4 elements is : [4 5 6 7]
slice3 elements is : [1 2 3 4 5 6 7 10]
slice4 elements is : [4 5 6 7 10]

http://www.ppmy.cn/embedded/119628.html

相关文章

Thread

一、thread类 创建线程使用std::thread类 #include <iostream> #include <thread> //必须包含<thread>头文件 void threadFunctionA() { std::cout << "Run New thread: 1" << std::endl; } void threadFunctionB(int n) { …

「OC」多线程的学习——NSThread

「OC」多线程的学习——NSThread 文章目录 「OC」多线程的学习——NSThread线程(process) 和 进程(thread) 的区别多线程NSThreadNSThread的创建NSThread的方法常见API线程状态控制方法 NSThread线程的状态 NSThread的多线程隐患售票窗口例子 synchronize关键字NSThread的线程通…

JavaScript中的输出方式

1. console.log() console.log() 是开发者在调试代码时最常用的方法。它将信息打印到浏览器的控制台&#xff0c;使开发者能够查看变量的值、程序的执行状态以及其他有用的信息。 用途&#xff1a;用于调试和记录程序运行时的信息。优点&#xff1a;简单易用&#xff0c;适合…

OpenCV特征检测(9)检测图像中直线的函数HoughLines()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在二值图像中使用标准 Hough 变换查找直线。 该函数实现了用于直线检测的标准 Hough 变换或标准多尺度 Hough 变换算法。详见 http://homepages…

【VUE_ruoyi-vue】基于ruoyi-vue框架实现简单的系统通用文件模块

基于ruoyi-vue框架&#xff0c;新增一个简单的系统通用文件模块&#xff0c;服务与各个模块涉及到文件上传信息的记录和相关展示 运行sql,创建数据库表 DROP TABLE IF EXISTS sys_file_info; CREATE TABLE sys_file_info (id int(11) NOT NULL AUTO_INCREMENT COMMENT id,lin…

Java基础扫盲(二)

想看Java基础扫盲&#xff08;一&#xff09;的可以观看我的上篇文章Java基础扫盲 目录 String为什么设计为不可变的 String有长度限制吗 为什么JDK9将String的char[]改为byte[] 泛型中K,T,V,E,Object,?等都代表什么含义 怎么修改一个类中使用了private修饰的String类型…

【OS】计算机系统概述|操作系统基本概念|并发|并行|虚拟异步

✨ Blog’s 主页: 白乐天_ξ( ✿&#xff1e;◡❛) &#x1f308; 个人Motto&#xff1a;他强任他强&#xff0c;清风拂山冈&#xff01; &#x1f525; 所属专栏&#xff1a;C深入学习笔记 &#x1f4ab; 欢迎来到我的学习笔记&#xff01; 前言 一、操作系统的概念 操作系统…

【web网页制作】html+css旅游家乡河南开封主题网页制作(4页面)【附源码】

HTMLCSS家乡河南主题网页目录 &#x1f354;涉及知识&#x1f964;写在前面&#x1f367;一、网页主题&#x1f333;二、页面效果Page1 首页Page2 开封游玩Page 3 开封美食Page4 留言 &#x1f308; 三、网页架构与技术3.1 脑海构思3.2 整体布局3.3 技术说明书 &#x1f40b;四…