Go语言必知必会100问题-20 切片操作实战

前言

有很多gopher将切片的length和capacity混淆,没有彻底理清这两者的区别和联系。理清楚切片的长度和容量这两者的关系,有助于我们合理的对切片进行初始化、通过append追加元素以及进行复制等操作。如果没有深入理解它们,缺少高效操作切片的方法,甚至可能导致内存泄露。

切片结构

Go语言中切片的底层是一个数组,也就是说切片中的元素在内存中是连续存储的。如果底层数组元素已满,继续向切片中添加元素,切片会进行扩容操作。在内部实现上,切片包含一个指向底层数组的指针,一个记录数组长度的字段和一个记录数组容量的字段。长度记录的是切片中已添加的元素数量,而容量记录的是数组大小。

切片初始化

下面结合几个具体的程序进行理解。首先来初始化一个给定长度和容量的切片:

s := make([]int, 3, 6)

通过make函数创建切片,它的第一个参数(3)表示切片的长度,是必传参数。第二个参数(6)是非必传参数,该参数表示切片的容量。下图展示了切片s在内存中的分配结果。

在这里插入图片描述

s的底层是一个包含6个元素(容量)的数组,但是因为长度设置为3,所以只初始化了前3个元素。又因为切片中的元素是int类型,所以初始的值为int的类型零值:0. 上图中灰色的格子表示已分配内存但尚未使用。

如果打印切片s的值,得到输出内容是长度范围内的元素值,即[0 0 0]. 如果将s[1]设置为1,则切片中的第二个元素内容会被更新为1,但不会影响切片s的长度和容量。

在这里插入图片描述

访问切片中的元素位置超过切片的长度是不被允许的,将会产生panic, 尽管已经分配的元素个数(切片的容量)比长度大。 例如,下面执行 s[4]=0将会产生pani.

panic: runtime error: index out of range [4] with length 3
append操作

那如何使用剩余灰色的3个空间呢?通过内置的append函数向切片中添加元素。

s = append(s, 2)

可以看到,通过append操作,切片s中添加了一个新的元素2. 元素2存在s中已分配但未使用的空间中(即数组中第4个格子)。如下图所示。此时s的长度变为4.

在这里插入图片描述

如果继续向s添加元素3、4、5, 这个时候元素个数已超过预分配的大小6,此时如何处理呢?

s = append(s, 3, 4, 5)
fmt.Println(s)

执行上面的代码,可以看到输出结果与我们预期的一致,打印 [0 1 0 2 3 4 5].

因为数组是一种大小固定的数据结构,s底层是一个大小为6的数组,所以它只能存储到元素4. 当向里面插入元素5的时候,它已经满了,这时将创建一个新的数组,数组的大小是原来的两倍,然后将原来数组中的元素拷贝到新数组中,最后向新数组中插入元素。处理结果如下图。

在这里插入图片描述

NOTE:在Go语言中,切片在扩容时,新切片的容量大小是旧切片的两倍,直到容量大小为1024,当容量超过1024时,按原来的1.25倍进行扩容。

现在切片s底层关联的是一个新数组,那之前的数组会怎么处理呢?如果它不再被引用,并且是在堆上分配的,则最后将被垃圾回收器(GC)回收。

截取操作

切片截取操作,截取操作的对象是一个数组或切片,从中截取一部分数据,截取的范围是左闭右开区间。下面的代码中,s2是通过截取s1得到的,在内存的结构如下图所示。

s1 := make([]int, 3, 6)
s2 := s1[1:3]

在这里插入图片描述

s1是一个长度为3,容量为6的切片,切片s2是通过s1创建的,两个切片底层引用的是相同的数组。但是,s2下标索引从底层数组的索引1开始,并且容量也与s1不同。如果我们对s1[1]或s2[0]进行更新操作,它们更改的是的底层数组的相同位置值,所以对s1[1]进行更新,将其设置为1,s2[0]的值也同步更新了,此时内存结构如下图所示。

在这里插入图片描述

如果此时执行 s2 = append(s2,2)操作,切片s1会发生变化吗?虽然它们共享的底层数组中的元素已发生变化,第4个格子中的元素被设置为2,但是该索引位置对s1是不可见的,因为它的长度为3, 此时s1和s2在内存中的结构如下。

在这里插入图片描述

现在打印s1和s2的值,输出如下。可以看到,它们的值是不同的,理解这种行为很重要,这样在使用append时就不会做出错误的假设。

s1=[0 1 0], s2=[1 0 2]

NOTE: 切片的底层数组是内部实现,Go开发人员是无法直接操作访问的。唯一的例外是通过对现有数组创建切片。

切片扩容

最后要考虑的一件事是,如果我们不断的将元素append到切片s2中,直到底层数组已满。继续append会产生什么效果?下面通过实验进行说明,继续向s2中append 3个元素.

s2 = append(s2, 3)
s2 = append(s2, 4)
s2 = append(s2, 5)

这样导致会分配一个新的底层数组给s2,因为原来的底层数组已不够容纳元素3、4、5. 此时s1和s2在内存中的结构如下图所示。可以看到,此时s1和s2底层引用的是不同的数组。由于s1是一个长度为3、容量为6的切片,并且它里面装的元素未满,所以继续引用原来的数组。s2新关联新的数组,并且会将s1中与之关联的数据拷贝到新数组中。

在这里插入图片描述

总结

切片长度是切片中已有元素的数量,而切片容量是切片中可以容纳的元素数量。向切片中添加元素,当长度和容量相等时会导致创建具有新容量的新底层数组,复制所有来自前一个数组的元素,并将切片指针更新为新数组。

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

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

相关文章

云服务器python版本冲突解决(awd平台搭建)

文章目录 yum和apt-getdockerpython环境问题 大家在使用python时,难免会使用他人的代码,自己是python3,而别人的是python2.我们直接运行会报错(比如print函数括号的问题)。但是去修改代码又很麻烦。这里给大家推荐conda。我以我搭建awd平台为…

【Java.mysql】——增删查改(CRUD)之 增查(CR) 附加数据库基础知识

目录 🚩数据库操作 🎈创建数据库 🎈使用数据库 🎈删除数据库 🚩数据类型 🚩表的操作 🎈创建表 🌈查看表结构 🎈删除表 ❗练习(综合运用) 🖥️新增…

微信小程序提示确认框

如图所示,如何弹出微信小程序自带默认弹框? 代码如下: wx.showModal({ title: 确认, content: 确定要删除吗?, success (res) { if (res.confirm) { console.log(用户点击确定) } else if (res.cancel) { console.log(用…

STM32CubeIDE基础学习-STM32CubeIDE软件程序仿真调试

STM32CubeIDE基础学习-STM32CubeIDE软件程序仿真调试 前言 一般编写完程序后都会进行编译,看结果是否有存在语法错误,确认没有语法错误之后再进行代码的下载观察硬件执行是否和软件编程预期的结果一致,如果发现硬件执行达不到预期现象&#…

JWT令牌技术

写在前面 我以为,最美的日子,当是晨起侍花,闲来煮茶,阳光下打盹,细雨中漫步,夜灯下读书,在这清浅时光里,一半烟火,一半诗意,任窗外花开花落,云来云…

no main manifest attribute,in xxx.jar(关于Spring项目,无法在云服务器上运行jar包的解决方法)

目录 问题详情 解决方法 问题详情 项目可以打包正常&#xff0c;但是云服务器上无法运行&#xff0c;报错&#xff1a;no main manifest attribute&#xff0c;in xxx.jar 解决方法 1.查看pom.xml配置文件&#xff0c;检查以下代码&#xff0c;没有则加上&#xff1a; <…

B+树 和 跳表 的结构及区别,不同的用途【mysql的索引为什么使用B+树而不使用跳表?】

导语&#xff1a; 详解B树与跳表的结构及区别&#xff0c;描述B树与跳表新增数据的过程&#xff0c;解释MySQL与Redis选择对应结构的原因。 mysql数据表里直接遍历这一行行数据&#xff0c;性能就是O(n)&#xff0c;比较慢。为了加速查询&#xff0c;使用了B树来做索引&#x…

HTML5 Web Worker之性能优化

描述 由于 JavaScript 是单线程的&#xff0c;当执行比较耗时的任务时&#xff0c;就会阻塞主线程并导致页面无法响应&#xff0c;这就是 Web Workers 发挥作用的地方。它允许在一个单独的线程&#xff08;称为工作线程&#xff09;中执行耗时的任务。这使得 JavaScript 代码可…

第三周组会——动态多目标优化算法

首先对上周写的DF测试函数进行了优化和增加 DF4 pf: DF5测试函数PF DF6 遇到的问题,在算法问题的参数taut(变化频率)默认是10数字变小时就算是9,算法会跟不上收敛 新读的文献 A Novel Dynamic Multiobjective Optimization Algorithm With Hierarchical Response System 一…

1.2_3 TCP/IP参考模型

文章目录 1.2_3 TCP/IP参考模型&#xff08;一&#xff09;OSI参考模型与TCP/IP参考模型&#xff08;二&#xff09;5层参考模型&#xff08;三&#xff09;5层参考模型的数据封装与解封装 1.2_3 TCP/IP参考模型 &#xff08;一&#xff09;OSI参考模型与TCP/IP参考模型 TCP/I…

【理解指针(1)】

理解指针&#xff08;1&#xff09; 1什么是内存2指针变量和地址21 取地址操作符&#xff08;&&#xff09;22 指针变量23 解引用操作符&#xff08;*&#xff09;24 指针变量的大小 3指针变量的意义31指针的解引用32 指针加减整数33 void* 指针 4. const 修饰指针41 const…

递归搜索回溯相关的题目解析和练习2

前言 大家好&#xff0c;我是jiantaoyab&#xff0c;下面的题目用的方法和前面几篇的方法是一样的&#xff0c;写起来是比较困难的&#xff0c;加油 字母大小写全排列 https://leetcode.cn/problems/letter-case-permutation/ 解析 代码 class Solution {vector<string&g…

【Docker】容器的概念

容器技术&#xff1a;容器技术是基于虚拟化技术的&#xff0c;它使应用程序从一个计算机环境快速可靠地转移到另一个计算机环境中&#xff0c;可以说是一个新型地虚拟化技术。 一、docker容器 Docker:是一个开源地容器引擎Docker 是一种轻量级的容器化技术&#xff0c;其主要原…

分割模型TransNetR的pytorch代码学习笔记

这个模型在U-net的基础上融合了Transformer模块和残差网络的原理。 论文地址&#xff1a;https://arxiv.org/pdf/2303.07428.pdf 具体的网络结构如下&#xff1a; 网络的原理还是比较简单的&#xff0c; 编码分支用的是预训练的resnet模块&#xff0c;解码分支则重新设计了。…

PyTorch搭建LeNet训练集详细实现

一、下载训练集 导包 import torch import torchvision import torch.nn as nn from model import LeNet import torch.optim as optim import torchvision.transforms as transforms import matplotlib.pyplot as plt import numpy as npToTensor()函数&#xff1a; 把图像…

git学习(创建项目提交代码)

操作步骤如下 git init //初始化git remote add origin https://gitee.com/aydvvs.git //建立连接git remote -v //查看git add . //添加到暂存区git push 返送到暂存区git status // 查看提交代码git commit -m初次提交git push -u origin "master"//提交远程分支 …

微信小程序(五十二)开屏页面效果

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.使用控件模拟开屏界面 2.倒计时逻辑 3.布局方法 4.TabBar隐藏复现 源码&#xff1a; components/openPage/openPage.wxml <view class"openPage-box"><image src"{{imagePath}}"…

三维不同坐标系下点位姿态旋转平移变换

文章目录 前言正文计算方法思路Python实现总结前言 本文主要说明以下几种场景3D变换的应用: 3D相机坐标系下长方体物体,有本身坐标系,沿该物体长边方向移动一段距离,并绕长边轴正旋转方向转90度,求解当前物体中心点在相机坐标系下的位置和姿态多关节机器人末端沿工具坐标…

STM32 利用FlashDB库实现在线扇区数据管理不丢失

STM32 利用FlashDB库实现在线扇区数据管理不丢失 &#x1f4cd;FalshDB地址:https://gitee.com/Armink/FlashDB ✨STM32没有片内EEPROM这样的存储区&#xff0c;虽然有备份寄存器&#xff0c;仅可以实现对少量数据的频繁存储&#xff0c;但是依赖备份电源&#xff08;BAT引脚&a…

美国签证|附面签相关事项√

小伙伴最近都忙着办签证吧&#xff01;但是需要注意的是&#xff0c;美国的签证跟其他任何国家的签证不同&#xff0c;并不是办理了就一定拿得到&#xff0c;据说概率是50%左右。所以办理美国签证&#xff0c;不要太着急啦&#xff01;先来了解一下美国签证的相片该怎么拍叭 ✅…