Go语言基础之切片
切片
切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。
切片是一个引用类型,它的内部结构包含地址、长度和容量。切片一般用于快速地操作一块数据集合
切片的定义
声明切片类型的基本语法如下:
var name []T
其中,
- name:表示变量名
- T:表示切片中的元素类型
举个例子:
func main() {// 声明切片类型var a []string //声明一个字符串切片var b = []int{} //声明一个整型切片并初始化var c = []bool{false, true} //声明一个布尔切片并初始化var d = []bool{false, true} //声明一个布尔切片并初始化fmt.Println(a) //[]fmt.Println(b) //[]fmt.Println(c) //[false true]fmt.Println(a == nil) //truefmt.Println(b == nil) //falsefmt.Println(c == nil) //false// fmt.Println(c == d) //切片是引用类型,不支持直接比较,只能和nil比较
}
切片的长度和容量
切片拥有自己的长度和容量,我们可以通过使用内置的len()函数求长度,使用内置的cap()函数求切片的容量。
切片表达式
切片表达式从字符串、数组、指向数组或切片的指针构造子字符串或切片。它有两种变体:一种指定low和high两个索引界限值的简单的形式,另一种是除了low和high索引界限值外还指定容量的完整的形式。
简单切片表达式
切片的底层就是一个数组,所以我们可以基于数组通过切片表达式得到切片。 切片表达式中的low和high表示一个索引范围(左包含,右不包含),也就是下面代码中从数组a中选出1<=索引值<4的元素组成切片s,得到的切片长度=high-low,容量等于得到的切片的底层数组的容量
func main() {a := [5]int{1, 2, 3, 4, 5}s := a[1:3] // s := a[low:high]fmt.Printf("s:%v len(s):%v cap(s):%v\n", s, len(s), cap(s))
}
输出:
s:[2 3] len(s):2 cap(s):4
为了方便起见,可以省略切片表达式中的任何索引。省略了low则默认为0;省略了high则默认为切片操作数的长度:
a[2:] // 等同于 a[2:len(a)]
a[:3] // 等同于 a[0:3]
a[:] // 等同于 a[0:len(a)]
注意:
对于数组或字符串,如果0 <= low <= high <= len(a),则索引合法,否则就会索引越界(out of range)。
对切片再执行切片表达式时(切片再切片),high的上限边界是切片的容量cap(a),而不是长度。常量索引必须是非负的,并且可以用int类型的值表示;对于数组或常量字符串,常量索引也必须在有效范围内。如果low和high两个指标都是常数,它们必须满足low <= high。如果索引在运行时超出范围,就会发生运行时panic。
func main() {a := [5]int{1, 2, 3, 4, 5}s := a[1:3] // s := a[low:high]fmt.Printf("s:%v len(s):%v cap(s):%v\n", s, len(s), cap(s))s2 := s[3:4] // 索引的上限是cap(s)而不是len(s)fmt.Printf("s2:%v len(s2):%v cap(s2):%v\n", s2, len(s2), cap(s2))
}
输出:
s:[2 3] len(s):2 cap(s):4
s2:[5] len(s2):1 cap(s2):1
完整切片表达式
对于数组,指向数组的指针,或切片a(注意不能是字符串)支持完整切片表达式:
a[low : high : max]
上面的代码会构造与简单切片表达式a[low: high]相同类型、相同长度和元素的切片。另外,它会将得到的结果切片的容量设置为max-low。在完整切片表达式中只有第一个索引值(low)可以省略;它默认为0。
func main() {a := [5]int{1, 2, 3, 4, 5}t := a[1:3:5]fmt.Printf("t:%v len(t):%v cap(t):%v\n", t, len(t), cap(t))
}
输出结果:
t:[2 3] len(t):2 cap(t):4
完整切片表达式需要满足的条件是0 <= low <= high <= max <= cap(a),其他条件和简单切片表达式相同。
使用make()函数构造切片
我们上面都是基于数组来创建的切片,如果需要动态的创建一个切片,我们就需要使用内置的make()函数,格式如下:
make([]T, size, cap)
其中:
- T:切片的元素类型
- size:切片中元素的数量
- cap:切片的容量
举个例子:
func main() {a := make([]int, 2, 10)fmt.Println(a) //[0 0]fmt.Println(len(a)) //2fmt.Println(cap(a)) //10
}
上面代码中a的内部存储空间已经分配了10个,但实际上只用了2个。 容量并不会影响当前元素的个数,所以len(a)返回2,cap(a)则返回该切片的容量。
切片的本质
切片的本质就是对底层数组的封装,它包含了三个信息:底层数组的指针、切片的长度(len)和切片的容量(cap)。
举个例子,现在有一个数组a := [8]int{0, 1, 2, 3, 4, 5, 6, 7},切片s1 := a[:5],相应示意图如下。

切片s2 := a[3:6],相应示意图如下:

判断切片是否为空
要检查切片是否为空,请始终使用len(s) == 0来判断,而不应该使用s == nil来判断。
切片不能直接比较
切片之间是不能比较的,我们不能使用==操作符来判断两个切片是否含有全部相等元素。 切片唯一合法的比较操作是和nil比较。 一个nil值的切片并没有底层数组,一个nil值的切片的长度和容量都是0。但是我们不能说一个长度和容量都是0的切片一定是nil,例如下面的示例:
var s1 []int //len(s1)=0;cap(s1)=0;s1==nil
s2 := []int{} //len(s2)=0;cap(s2)=0;s2!=nil
s3 := make([]int, 0) //len(s3)=0;cap(s3)=0;s3!=nil
所以要判断一个切片是否是空的,要是用len(s) == 0来判断,不应该使用s == nil来判断。
切片的赋值拷贝
下面的代码中演示了拷贝前后两个变量共享底层数组,对一个切片的修改会影响另一个切片的内容,这点需要特别注意。
func main() {s1 := make([]int, 3) //[0 0 0]s2 := s1 //将s1直接赋值给s2,s1和s2共用一个底层数组s2[0] = 100fmt.Println(s1) //[100 0 0]fmt.Println(s2) //[100 0 0]
}
切片遍历
切片的遍历方式和数组是一致的,支持索引遍历和for range遍历。
func main() {s := []int{1, 3, 5}for i := 0; i < len(s); i++ {fmt.Println(i, s[i])}for index, value := range s {fmt.Println(index, value)}
}
append()方法为切片添加元素
Go语言的内建函数append()可以为切片动态添加元素。 可以一次添加一个元素,可以添加多个元素,也可以添加另一个切片中的元素(后面加…)。
func main(){var s []ints = append(s, 1) // [1]s = append(s, 2, 3, 4) // [1 2 3 4]s2 := []int{5, 6, 7} s = append(s, s2...) // [1 2 3 4 5 6 7]
}
注意:通过var声明的零值切片可以在append()函数直接使用,无需初始化。
var s []int
s = append(s, 1, 2, 3)
没有必要像下面的代码一样初始化一个切片再传入append()函数使用,
s := []int{} // 没有必要初始化
s = append(s, 1, 2, 3)var s = make([]int) // 没有必要初始化
s = append(s, 1, 2, 3)
每个切片会指向一个底层数组,这个数组的容量够用就添加新增元素。当底层数组不能容纳新增的元素时,切片就会自动按照一定的策略进行“扩容”,此时该切片指向的底层数组就会更换。“扩容”操作往往发生在append()函数调用时,所以我们通常都需要用原变量接收append函数的返回值。
举个例子:
func main() {//append()添加元素和切片扩容var numSlice []intfor i := 0; i < 10; i++ {numSlice = append(numSlice, i)fmt.Printf("%v len:%d cap:%d ptr:%p\n", numSlice, len(numSlice), cap(numSlice), numSlice)}
}
输出:
[0] len:1 cap:1 ptr:0xc0000a8000
[0 1] len:2 cap:2 ptr:0xc0000a8040
[0 1 2] len:3 cap:4 ptr:0xc0000b2020
[0 1 2 3] len:4 cap:4 ptr:0xc0000b2020
[0 1 2 3 4] len:5 cap:8 ptr:0xc0000b6000
[0 1 2 3 4 5] len:6 cap:8 ptr:0xc0000b6000
[0 1 2 3 4 5 6] len:7 cap:8 ptr:0xc0000b6000
[0 1 2 3 4 5 6 7] len:8 cap:8 ptr:0xc0000b6000
[0 1 2 3 4 5 6 7 8] len:9 cap:16 ptr:0xc0000b8000
[0 1 2 3 4 5 6 7 8 9] len:10 cap:16 ptr:0xc0000b8000
从上面的结果可以看出:
- append()函数将元素追加到切片的最后并返回该切片。
- 切片numSlice的容量按照1,2,4,8,16这样的规则自动进行扩容,每次扩容后都是扩容前的2倍。
append()函数还支持一次性追加多个元素。 例如:
var citySlice []string
// 追加一个元素
citySlice = append(citySlice, "北京")
// 追加多个元素
citySlice = append(citySlice, "上海", "广州", "深圳")
// 追加切片
a := []string{"成都", "重庆"}
citySlice = append(citySlice, a...)
fmt.Println(citySlice) //[北京 上海 广州 深圳 成都 重庆]
使用copy()函数复制切片
func main() {a := []int{1, 2, 3, 4, 5}b := afmt.Println(a) //[1 2 3 4 5]fmt.Println(b) //[1 2 3 4 5]b[0] = 1000fmt.Println(a) //[1000 2 3 4 5]fmt.Println(b) //[1000 2 3 4 5]
}
由于切片是引用类型,所以a和b其实都指向了同一块内存地址。修改b的同时a的值也会发生变化。
Go语言内建的copy()函数可以迅速地将一个切片的数据复制到另外一个切片空间中,copy()函数的使用格式如下:
copy(destSlice, srcSlice []T)
其中:
- srcSlice: 数据来源切片
- destSlice: 目标切片
举个例子:
func main() {// copy()复制切片a := []int{1, 2, 3, 4, 5}c := make([]int, 5, 5)copy(c, a) //使用copy()函数将切片a中的元素复制到切片cfmt.Println(a) //[1 2 3 4 5]fmt.Println(c) //[1 2 3 4 5]c[0] = 1000fmt.Println(a) //[1 2 3 4 5]fmt.Println(c) //[1000 2 3 4 5]
}
从切片中删除元素
Go语言中并没有删除切片元素的专用方法,我们可以使用切片本身的特性来删除元素。 代码如下:
func main() {// 从切片中删除元素a := []int{30, 31, 32, 33, 34, 35, 36, 37}// 要删除索引为2的元素a = append(a[:2], a[3:]...)fmt.Println(a) //[30 31 33 34 35 36 37]
}
总结一下就是:要从切片a中删除索引为index的元素,操作方法是a = append(a[:index], a[index+1:]…)
相关文章:
Go语言基础之切片
切片 切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。 切片是一个引用类型,它的内部结构包含地址、长度和容量。切片一般用于快速地操作一块数据集合 切片的定义…...
关于java三元组的问题
在改代码的时候,发现一个奇怪的地方,举例如下 Testpublic void buildTest(){TT t new TT();Long time tnull?System.currentTimeMillis():t.getTime();System.out.println("done");}Datapublic static class TT{Long time;}这个地方运行就…...
如何正确地设置Outlook SMTP发送电子邮件(wordpress配置)
如何正确地设置Outlook SMTP发送电子邮件(wordpress配置) 作者:虚坏叔叔 博客:https://pay.xuhss.com 早餐店不会开到晚上,想吃的人早就来了!😄 正在寻找正确的Outlook SMTP设置?…...
机器学习编译系列---张量程序抽象
机器学习编译系列---张量程序抽象 1. 张量函数概念的引入与抽象的必要性 1. 张量函数概念的引入与抽象的必要性 在文章机器学习编译系列—概述中提到,机器学习编译的一个很重要操作是做等价变换来减少内存或者提高运行效率。变换是以“元张量函数”(private tensor …...
python使用matplotlib实现折线图的绘制
一、意义 数据可视化可以以简洁的方式呈现出数据,发现众多数据中隐藏的规律和意义。Matplotlib是一个数学绘图库。利用它可以制作简单的图表(散点图、折线图)。然后,将基于漫步概念生成一个更有趣的数据集–根据一系列随机决策生成…...
网络协议的定义、组成和重要性?
什么是网络协议? 网络协议是在计算机网络中,用于规定通信实体之间进行数据传输和通信的规则集合。网络协议涵盖了各种通信细节,包括数据包格式、错误处理、数据传输速率等,是用于分组交换数据网络的一种协议,其任务仅…...
vue 使用print.js打印小票
官网:https://printjs.crabbly.com/ // 安装 npm install print-js --save// 引入 import printJS from print-js// 使用 printJS({printable: https://hwke.tbbug.com/images/phone/1899ed9346f64020ff4f9bbae6983952.jpg,type: image,imageStyle: width:100%;ma…...
算法通关村第6关【白银】| 树的层次遍历问题
一、基本层次遍历问题 1.二叉树的层次遍历 思路:使用队列可以很好的保存遍历状态,出队将结点左右子结点入队,用size记录下一层的元素个数,这样就能区分出层了 class Solution {public List<List<Integer>> levelOr…...
Qt与电脑管家3
1.ui页面设计技巧 最外面的widget: 上下左右的margin都置相同的值 这里有4个widget,做好一个后,后面3个可以直接复制.ui文件,然后进行微调即可。 2.现阶段实现的效果: 3.程序结构: btn1--->btn btn1---…...
Jmeter 快速生成测试报告
我们使用Jmeter工具进行接口测试或性能测试后一般是通过察看结果数、聚合报告等监听器来查看响应结果。如果要跟领导汇报测试结果,无法直接通过监听器的结果来进行展示和汇报,因为太low了,因此测试完成后去整理一个数据齐全且美观的报告是非常…...
消息队列——RabbitMQ(一)
MQ的相关概念 什么事mq MQ(message queue),从字面意思上看,本质是个队列,FIFO 先入先出,只不过队列中存放的内容是 message 而已,还是一种跨进程的通信机制,用于上下游传递消息。在互联网架构中ÿ…...
人工智能在机器学习中的八大应用领域
文章目录 1. 自然语言处理(NLP)2. 图像识别与计算机视觉3. 医疗诊断与影像分析4. 金融风险管理5. 预测与推荐系统6. 制造业和物联网7. 能源管理与环境保护8. 决策支持与智能分析结论 🎉欢迎来到AIGC人工智能专栏~探索人工智能在机器学习中的八…...
vue3+ts使用vue-i18n
vue3ts使用vue-i18n 1、安装插件 npm install --save vue-i18nyarn add vue-i18n2、配置文件 locale/index.ts import { createI18n } from vue-i18n import zhCN from ./lang/zh-CN import enUS from ./lang/en-USexport const LOCALE_OPTIONS [{ label: 中文, value: zh…...
在Ubuntu上安装和设置RabbitMQ服务器,轻松实现外部远程访问
文章目录 前言1.安装erlang 语言2.安装rabbitMQ3. 内网穿透3.1 安装cpolar内网穿透(支持一键自动安装脚本)3.2 创建HTTP隧道 4. 公网远程连接5.固定公网TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 前言 RabbitMQ是一个在 AMQP(高级消息队列协议)基…...
Redis多机实现
Background 为啥要有多机--------------1.容错 2.从服务器分担读压力。 主从结构一大难题------------如何保障一致性,对这个一致性要求不是很高,因为redis是用来做缓存的 同时我们要自动化进行故障转移-------哨兵机制,同时哨兵也可能cra…...
ClickHouse安装及部署
文章目录 Docker快速安装Ubuntu预编译安装包安装检查是否支持SSE4.2使用预编译安装包 Tgz安装包配置文件修改修改密码配置远程访问 其他主机访问文章参考 Docker快速安装 本地pull镜像 docker run -d --name ch-server --ulimit nofile262144:262144 -p 9000:9000 -p 8123:81…...
[HarekazeCTF2019]Easy Notes-代码审计
文章目录 [HarekazeCTF2019]Easy Notes-代码审计 [HarekazeCTF2019]Easy Notes-代码审计 登录之后有几个功能点,可以添加节点,然后使用Export导出 我们查看源码, 我们发现想要拿到flag的条件时$_SESSION[admin]true 如果我们能够控制sessio…...
nginx-location正则
一 Nginx的location语法 location [||*|^~] /uri/ { … } 严格匹配。如果请求匹配这个location,那么将停止搜索并立即处理此请求~ 区分大小写匹配(可用正则表达式)~* 不区分大小写匹配(可用正则表达式)!~ 区分大小写不匹配!~* 不区分大小写不匹配^~ 如果把这个前缀…...
微信小程序胶囊位置计算,避开胶囊位置
由于小程序在不同的手机上顶部布局会发生变化,不能正确避开胶囊位置,所以通过官方给出的胶囊信息,可以计算出胶囊位置,并避开 图示例: 此处思路是,获取胶囊底部位置,并拉开10个px 计算出来的…...
快速指南:使用Termux SFTP通过远程进行文件传输——”cpolar内网穿透“
文章目录 1. 安装openSSH2. 安装cpolar3. 远程SFTP连接配置4. 远程SFTP访问4. 配置固定远程连接地址 SFTP(SSH File Transfer Protocol)是一种基于SSH(Secure Shell)安全协议的文件传输协议。与FTP协议相比,SFTP使用了…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
