go语言切片
切片
切片是一种数据结构,这种数据结构便于使用和管理数据集合。切片是围绕动态数组的概念构建的,可以按需自动增长和缩小。切片的动态增长是通过内置函数 append 来实现的。这个函数可以快速且高效地增长切片。还可以通过对切片再次切片来缩小一个切片的大小。因为切片的底层内存也是在连续块中分配的,所以切片还能获得索引、迭代以及为垃圾回收优化的好处。
- 声明切片:
- 使用
var
关键字声明切片。 - 指定切片的类型。
- 初始化切片:
- 可以在声明时初始化切片。
- 也可以使用
make
函数创建切片。
- 访问切片元素:
- 使用索引访问切片中的元素。
- 切片的长度和容量:
- 使用内置函数
len
获取切片的长度。 - 使用内置函数
cap
获取切片的容量。
- 切片的动态扩展:
- 使用
append
函数动态扩展切片。
[]int
[]interface{}
内部实现
在运行期间,Slice是由如下的SliceHeader结构体进行表示的
type SliceHeader struct {Data uintptr // 数组指针Len int // 长度Cap int // 容量
}
这 3 个字段分别是指向底层数组的指针、切片访问的元素的个数(即长度)和切片允许增长到的元素个数(即容量)
和C++的vector一样,在进行扩容时,一般会大于实际需要的长度,在实际使用中能有效的减少扩容的次数。
空切片和nil切片
空切片和nil切片并不等价,空切片和nil切片是不同的。空切片是一个长度为0,容量为0的切片,而nil切片是一个未初始化的切片,它指向一个不存在的内存区域。
创建一个nil切片非常简单,只需要声明一个切片变量,而不需要初始化。
// 定义一个nil切片
var slice []int
// 定义一个nil切片
slice := []int(nil)
创建一个空切片,需要使用make函数来创建,但是指定长度和容量为0
slice := make([]int, 0)
当使用make指定的切片长度为0时,那么底层其实会创建一个指针指向zerobase的切片,这时的Data指向 &zerobase
// base address for all 0-byte allocations
var zerobase uintptr
每次调用make来创建切片,都会调用到runtime.slice.go中的makeslice函数,我们来看下当cap和len为0时makeslice的处理逻辑。
//len = 0, cap = 0
func makeslice(et *_type, len, cap int) unsafe.Pointer {// mem = 0, overflow = falsemem, overflow := math.MulUintptr(et.Size_, uintptr(cap))...return mallocgc(mem, et, true)
}func MulUintptr(a, b uintptr) (uintptr, bool) {// a|b < 1<<(4*goarch.PtrSize) 满足// a == 0 满足if a|b < 1<<(4*goarch.PtrSize) || a == 0 {// 这里会返回a * b = 0, overflow = falsereturn a * b, false}...
}
// 这里调用时 size = 0
func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {if gcphase == _GCmarktermination {throw("mallocgc called with gcphase == _GCmarktermination")}// size == 0if size == 0 {return unsafe.Pointer(&zerobase)}...
}
.空切片Data 为 &zerobase
使用示例
切片的初始化
- 通过下标方式获得数组或者切片的一部分
- 使用字面量对切片进行初始化
- 使用关键字make创建切片
// 使用空字符串初始化一个长度为100个元素的切片
slice := []string{99:""}
// 引用方式初始化切片
slice := arr[0:3]
// 切片字面量来声明一个长度为3的切片,容量为3的切片
slice := []int{1,2,3}
// 只指定长度,那么底层长度和容量相同
slie := make([]int, 10)
// 创建一个长度为10,容量为20的切片,需要确保长度<=容量,否则会报错
slice := make([]int, 10, 20)
使用for range迭代的是副本不是引用
// 创建一个整型切片
// 其长度和容量都是 4 个元素
slice := []int{10, 20, 30, 40}
// 迭代每一个元素,使用range迭代切片是副本
for index, value := range slice {fmt.Printf("Index: %d Value: %d\n", index, value)
}
slice := make([]int, 5, 20)
// 切片引用为前闭后开 [1,3)
sliceRef := slice[1:3]
// 切片长度为2,容量为 20 - 1,引用之后切片前端会从引用点开始,剩余元素保留
fmt.Println(len(sliceRef), cap(sliceRef))
// 修改引用切片的内容也会同步修改原切片
sliceRef[0] = 100
// slice[1] = 100
fmt.Println(slice[1])
// 当修改超过切片长度但是在容量范围内的元素时,会抛出panic
//slice[6] = 200
//函数 append 总是会增加新切片的长度,而容量有可能会改变,也可能不会改变,这取决于被操作的切片的可用容量。
slice = append(slice, 200)
//slice := source[low:high:max]
//source 是原始切片或数组。
//low 是切片的起始索引(包含)。
//high 是切片的结束索引(不包含)。
//max 是切片的最大容量位置(不包含)
slice := slice[2:4:10]// 如果容量设置大于已有容量,会出现运行时错误
source := [5]int{1, 2, 3, 4, 5}
slice := source[2:3:4]
//长度 (len(slice)):切片的长度是从 low 到 high 之间的元素数量,即 high - low。
//容量 (cap(slice)):切片的容量是从 low 到 max 之间的元素数量,即 max - low。
//对于 slice[i:j:k] 或 [2:3:4]
//长度: j – i 或 3 - 2 = 1
//容量: k – i 或 4 - 2 = 2
fmt.Println("Slice:", slice) // 输出: Slice: [3]
fmt.Println("Length:", len(slice)) // 输出: Length: 1
fmt.Println("Capacity:", cap(slice)) // 输出: Capacity: 2// 设置长度和切片容量一致的好处
// 创建字符串切片
// 其长度和容量都是 5 个元素
source := []string{"Apple", "Orange", "Plum", "Banana", "Grape"}
// 对第三个元素做切片,并限制容量
// 其长度和容量都是 1 个元素
slice := source[2:3:3]
// 向 slice 追加新字符串,因为引用时容量和长度一致,只要调用append() 方法,就会自动增加容量,
// 后面再修改引用切片就不会影响原切片的内容了
slice = append(slice, "Kiwi")
切片的子切片
package mainimport "fmt"func main() {// 创建一个整数切片numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}// 创建子切片,切片的引用subSlice := numbers[2:5] // 子切片从索引 2 到 4(不包括 5)// 打印子切片fmt.Println(subSlice) // 输出: [3 4 5]
}
切片使用注意事项
- 初始容量设置:合理设置初始容量,减少内存重新分配的次数。
- 避免不必要的拷贝:尽量减少频繁的
append
操作。 - 预分配足够的容量:如果可以预估最终大小,一次性分配足够的容量。
- 避免多次
append
操作:收集所有要添加的元素,一次性append
。 - 检查切片容量:在
append
前检查容量,必要时手动重新分配内存。 - 使用
copy
函数:在某些情况下,使用copy
函数可以更高效地复制数据。
避免不必要的拷贝
每次 append
操作超过当前切片的容量时,Go 会分配一个新的更大的底层数组,并将原有数据复制到新的数组中。频繁的拷贝操作会影响性能。
package mainimport "fmt"func main() {// 创建一个初始容量为 2 的切片numbers := make([]int, 0, 2)// 动态扩展切片for i := 1; i <= 15; i++ {numbers = append(numbers, i)}// 打印切片fmt.Println(numbers) // 输出: [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
}
预分配足够的容量
如果可以预估最终切片的大小,建议一次性分配足够的容量,以减少内存重新分配的次数。
package mainimport "fmt"func main() {// 创建一个初始容量为 15 的切片numbers := make([]int, 0, 15)// 动态扩展切片for i := 1; i <= 15; i++ {numbers = append(numbers, i)}// 打印切片fmt.Println(numbers) // 输出: [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
}
避免多次 append
操作,如果需要多次 append
操作,可以考虑先收集所有要添加的元素,然后一次性 append
。
package mainimport "fmt"func main() {// 创建一个初始容量为 10 的切片numbers := make([]int, 0, 10)// 收集要添加的元素newElements := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}// 一次性 appendnumbers = append(numbers, newElements...)// 打印切片fmt.Println(numbers) // 输出: [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
}
在进行 append
操作前,可以检查当前切片的容量,以决定是否需要重新分配内存。一旦发生内存重新分配,就会存在大规模的copy,因此一定要提前初始化足够的切片,避免冲突发生切片赋值的情况
package mainimport "fmt"func main() {// 创建一个初始容量为 10 的切片numbers := make([]int, 0, 10)// 动态扩展切片for i := 1; i <= 15; i++ {if cap(numbers) < len(numbers) + 1 {// 需要重新分配内存newCapacity := cap(numbers) * 2if newCapacity < len(numbers) + 1 {newCapacity = len(numbers) + 1}newSlice := make([]int, len(numbers), newCapacity)copy(newSlice, numbers)numbers = newSlice}numbers = append(numbers, i)}// 打印切片fmt.Println(numbers) // 输出: [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
}
在某些情况下,使用 copy
函数可以更高效地复制数据。
package mainimport "fmt"func main() {// 创建一个初始容量为 10 的切片numbers := make([]int, 0, 10)// 收集要添加的元素newElements := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}// 一次性 appendnumbers = append(numbers, newElements...)// 使用 copy 函数newNumbers := make([]int, len(numbers))copy(newNumbers, numbers)// 打印切片fmt.Println(newNumbers) // 输出: [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
}
相关文章:
go语言切片
切片 切片是一种数据结构,这种数据结构便于使用和管理数据集合。切片是围绕动态数组的概念构建的,可以按需自动增长和缩小。切片的动态增长是通过内置函数 append 来实现的。这个函数可以快速且高效地增长切片。还可以通过对切片再次切片来缩小一个切片的…...
鸿蒙NEXT元服务:利用App Linking实现无缝跳转与二维码拉起
【效果】 元服务链接格式(API>12适用):https://hoas.drcn.agconnect.link/ggMRM 【参考网址】 使用App Linking实现元服务跳转:文档中心 草料二维码:草料二维码生成器 【引言】 本文将详细介绍如何使用App Lin…...
网络药理学之薛定谔Schrödinge Maestro:6、分子对接(Glide、Ligand docking)和可视化
本人是win11,薛定谔版本是12.9。 官网:https://www.schrodinger.com/ 本篇文章的示例大分子蛋白PDB ID为4KNN,小分子配体的MOL ID为MOL004004。 本文部分图源来自知乎https://zhuanlan.zhihu.com/p/416698194,推荐为原作者贡献阅读…...
已解决ModuleNotFoundError: No module named ‘selenium‘
1. 错误提示 ModuleNotFoundError: No module named selenium,这意味着你试图导入一个名为 selenium 的模块,但Python找不到这个模块 2. 解决方案 安装缺失的模块: 如果你确定模块名称正确但仍然收到这个错误,那么可能是你没有安装这个模块…...
【Maven】依赖冲突如何解决?
准备工作 1、创建一个空工程 maven_dependency_conflict_demo,在 maven_dependency_conflict_demo 创建不同的 Maven 工程模块,用于演示本文的一些点。 什么是依赖冲突? 当引入同一个依赖的多个不同版本时,就会发生依赖冲突。…...
什么是EMS
EMS是能量管理系统(Energy Management System)的缩写,是一种集成的技术解决方案,旨在帮助企业和组织更有效地管理和优化其能源使用。EMS通过收集、分析和报告能源数据来识别节能机会,并提供工具以实施改进措施。 主要…...
26页PDF | 数据中台能力框架及评估体系解读(限免下载)
一、前言 这份报告详细解读了数据中台的发展历程、核心概念、能力框架及成熟度评估体系。它从阿里巴巴的“大中台,小前台”战略出发,探讨了数据中台如何通过整合企业内部的数据资源和能力,加速业务迭代、降低成本,并推动业务增长…...
【Vue3】【Naive UI】< a >标签
【Vue3】【Naive UI】< a >标签 超链接及相关属性其他属性 【VUE3】【Naive UI】<NCard> 标签 【VUE3】【Naive UI】<n-button> 标签 【VUE3】【Naive UI】<a> 标签 <a> 标签HTML中的一个锚&…...
分页查询日期格式不对
方式一:在属性上加入注解,对日期进行格式化 方式二:在 WebMvcConfiguration 中扩展Spring MVC的消息转换器,统一对日期类型进行格式化处理 /*** 统一转换处理扩展spring mvc* 后端返回前端的进行统一转化处理* param converters*/Overrideprotected voi…...
DAY140权限提升-Linux系统权限提升篇VulnhubPATH变量NFS服务Cron任务配合SUID
一、演示案例-Linux系统提权-Web&普通用户-SUID-NFS安全 NFS是一种基于TCP/IP 传输的网络文件系统协议,通过使用NFS协议,客户机可以像访问本地目录一样访问远程服务器中的共享资源。 https://www.virtualbox.org/wiki/Downloads https://www.vuln…...
HTTPS 的应用数据是如何保证完整性的?
在 HTTPS 中,确保 应用数据的完整性 是通过以下几个关键机制来实现的: 消息认证码(MAC):用于确保数据在传输过程中未被篡改。加密:通过加密数据防止数据被窃取,并与 MAC 配合使用,确…...
Unity ShaderLab 实现3D物体描边
实现思路: 给物体添加第二个材质球,在shader的顶点着色器中使顶点的位置变大,然后在片元着色器中输出描边颜色。 shader Graph实现如下: ShaderLab实现如下: Shader "Custom/Outline" {Properties{[HDR]_…...
SQL进阶——C++与SQL进阶实践
在C开发中,SQL数据库的操作是开发者常见的任务之一。虽然前面我们已经介绍了如何在C中通过数据库连接执行基本的SQL查询,但在实际项目中,我们通常需要更加复杂和高效的数据库操作。存储过程与函数的调用、复杂SQL查询的编写、以及动态构造SQL…...
AIGC--------AIGC在医疗健康领域的潜力
AIGC在医疗健康领域的潜力 引言 AIGC(Artificial Intelligence Generated Content,人工智能生成内容)是一种通过深度学习和自然语言处理(NLP)等技术生成内容的方式。近年来,AIGC在医疗健康领域展现出了极…...
node.js中实现MySQL的增量备份
有时候,我们需要对生产库进行备份,不要求实时性很高,大概每天一次就行,为性能考虑,只备份最新更改内容,即增量备份即可,这种场景下对DB的设计和备份语句有所要求。 首先要求按源表各字段定义目标…...
Java线程池提交任务流程底层源码与源码解析
前言 嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的…...
新型大语言模型的预训练与后训练范式,Meta的Llama 3.1语言模型
前言:大型语言模型(LLMs)的发展历程可以说是非常长,从早期的GPT模型一路走到了今天这些复杂的、公开权重的大型语言模型。最初,LLM的训练过程只关注预训练,但后来逐步扩展到了包括预训练和后训练在内的完整…...
硬菜3道+馒头
硬菜3道 1、可乐鸡翅 》鸡翅滑刀酱油耗油胡椒粉盐》 搅拌腌制3-5分钟 》油锅,直到2面煎黄 》倒入可乐,到大火收汁,出锅 2、洋葱牛肉 》冻牛肉切薄酱油耗油胡椒粉盐 》手指摇匀 》加入生粉水,继续摇匀》直到粘稠 》油锅牛肉炒半熟&…...
YOLO系列论文综述(从YOLOv1到YOLOv11)【第14篇:YOLOv11——在速度和准确性方面具有无与伦比的性能】
YOLOv11 1 摘要2 改进点3 模型性能4 模型架构 YOLO系列博文: 【第1篇:概述物体检测算法发展史、YOLO应用领域、评价指标和NMS】【第2篇:YOLO系列论文、代码和主要优缺点汇总】【第3篇:YOLOv1——YOLO的开山之作】【第4篇ÿ…...
【Spring】聊聊@EventListener注解原理
1.一个Demo出发 在平时的开发中,其实编写同步线程代码是比较容易的,但是如何将一些操作和另外一些操作进行解除耦合,而事件方式 是一种很好的解耦合方式,比如当一个用户注销一个APP之后,需要发送一些短信 让他引流回来…...
LangChain——HTML文本分割 多种文本分割
Text Splitters 文本分割器 加载文档后,您通常会想要对其进行转换以更好地适合您的应用程序。最简单的例子是,您可能希望将长文档分割成更小的块,以适合模型的上下文窗口。 LangChain 有许多内置的文档转换器,可以轻松地拆分、组…...
梯度爆炸与消失
梯度爆炸和梯度消失 一、概念解析 (一)梯度爆炸 定义 在深度神经网络训练的反向传播过程中,梯度爆炸是指梯度的值过大的现象。这会使模型的参数更新出现异常。 产生原因 深层网络与链式法则:深度神经网络按链式法则计算某层权重…...
关于扩散方程的解
1-D 扩散方程的形式 Cauchy齐次方程 这个解无积分无级数,很简单的形式 美其名曰:基本解。 把基本解和初值做卷积,就得到cauchy方程的解。...
如何监控Elasticsearch集群状态?
大家好,我是锋哥。今天分享关于【如何监控Elasticsearch集群状态?】面试题。希望对大家有帮助; 如何监控Elasticsearch集群状态? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 监控 Elasticsearch 集群的状态对于确保…...
关于音频 DSP 的接口种类以及其应用场景介绍
在音频系统中,DSP(数字信号处理器)扮演着重要角色,通常会通过不同的接口与音频系统中的其他组件(如功放、扬声器、音频源等)进行连接。以汽车应用场景为例,以下是一些常见的接口类型分类及其介绍…...
arkTS:持久化储存UI状态的基本用法(PersistentStorage)
arkUI:持久化储存UI状态的基本用法(PersistentStorage) 1 主要内容说明2 例子2.1 持久化储存UI状态的基本用法(PersistentStorage)2.1.1 源码1的相关说明2.1.1.1 数据存储2.1.1.2 数据读取2.1.1.3 动态更新2.1.1.4 显示…...
css—动画
一、背景 本文章是用于解释上一篇文章中的问题,如果会动画的小伙伴就不用再次来看了,本文主要讲解一下动画的设定规则,以及如何在元素中添加动画,本文会大篇幅的讲解一下,动画属性。注意,这是css3的内容&am…...
YOLO系列论文综述(从YOLOv1到YOLOv11)【第12篇:YOLOv9——可编程梯度信息(PGI)+广义高效层聚合网络(GELAN)】
YOLOv9 1 摘要2 改进点3 网络架构 YOLO系列博文: 【第1篇:概述物体检测算法发展史、YOLO应用领域、评价指标和NMS】【第2篇:YOLO系列论文、代码和主要优缺点汇总】【第3篇:YOLOv1——YOLO的开山之作】【第4篇:YOLOv2—…...
【ETCD】etcd简单入门之基础操作基于etcdctl进行操作
这里将使用etcdctl命令行工具来进行演示, 1、使用put命令向etcd写入kv对 使用etcdctl put命令来设置键值对。put命令接受两个参数:键和值 使用方法: NAME:put - Puts the given key into the storeUSAGE:etcdctl put [options] <key&g…...
第六届国际科技创新(IAECST 2024)暨第四届物流系统与交通运输(LSTT 2024)
重要信息 会议官网:www.lstt.org 大会时间:2024年12月6-8日 大会地点:中国-广州 简介 第六届国际科技创新暨第四届物流系统与交通运输国际(LSTT 2024)将于2024年12月6-8日在广州举办,这是一个集中探讨…...
iis7 wordpress 伪静态规则/seo排名优化资源
练习题2.1 一、选择题 1.函数导数是函数改变量与自变量改变量之比,当( D )趋于零时的极限. A.自变量;B.函数;C.函数的改变量;D.自变量改变量 解:依据导数定义:f ′ (x 0 )lim Δx→0 ΔyΔx ,可知选D \color{blue}{解:\\ 依据导数定义…...
景观设计公司利润/谷歌优化是什么意思
ftp服务很重要,这里介绍ftp在linux上不连接mysql数据库的搭建方法,ftp也可以连接mysql,有时间再生成文档。先说明ftp的基本原理:FTP �File Transfer Protocol 文件传输协议。能够在网络上提供文件传输服务,…...
网站浏览图片怎么做/关键词查询的分析网站
Lazarus crack,功能丰富的 Delphi 开发环境 Lazarus为开发人员提供了一个功能丰富的 Delphi 开发环境,使他们能够创建功能齐全的跨平台应用程序,专为个人和商业用途而设计。 Lazarus 项目拥有超过 15 年的历史,包括一个用于 Free Pascal 的综…...
做网站的手机软件/今日新闻最新头条10条摘抄
结直肠癌是常见的消化道肿瘤之一,我国的结直肠癌发病率和病死率均居于前列。近年来随着靶向治疗和免疫治疗在结直肠癌治疗中的应用,晚期结直肠癌的治疗进入了一个新的阶段。结直肠癌疗效预测和预后评估分子标志物对临床制订正确的治疗方案非常重要。在7月…...
深圳住房建设部官方网站/网站设计公司有哪些
Android 的 layout 文件中有时候可能会指定具体的单位,比如有时候为 px 、 dip 或者 sp 等。他们的区别如下: 1. px (pixels)像素:这个大家用得比较多,一般我们HVGA代表320x480像素。 2. dip或dp (device independent pixels)设…...
漯河市建设监理协会网站/百度优化插件
姓名 陈嘉 日期 2015/7/13 主要工作及心得 今天,我们将上周分工做的各部分组合起来,进行调试。结果和我们想的一样,根本不能运行。然后我们就开始了一天漫长的调试。 首先是数据从客户端,到服务器、数据库的传送…...