【Go基础】切片

news2024/12/28 3:58:59

切片

1. 切片的定义

切片(slice)是Golang中独有的数据类型。

数组有特定的用处,但是有不足之处 :运行时长度不可变。切片是随处可变的,它构建在数组之上,并且提供更强大的能力和便捷。

切片(slice)是对数组一个片段的引用,所以切片是引用数据类型。这个片段可以是整个数组,也可以是数组的一部分。

特点 :

  • 切片与其引用的数组共享内存地址

  • 虽然切片可变大,但是不能超过其引用的数组,使用cap(切片)的计算切片的长度。

    0 <= len(切片) <= cap(切片) <= len(arr)

  • 切片是数组的引用,但它是一个结构体,值传递。

切片的容量如何计算 :

切片容量为切片起始位置到数组结束位置的元素个数。假如从数组下标n开始切片,那么 cap(切片) = len(数组) - n

2. 切片的声明

2.1 空切片

声明一个数组,不指定其大小,该数组就是一个切片。

这个切片是一个空切片,它的值是 nil

var arr[]int
if arr == nil {
	fmt.Println("切片的元素数:", len(arr))// 0
	fmt.Println("切片的容量数:", cap(arr))// 0
	fmt.Println("切片的所有元素:", slice1)// []
	fmt.Println("arr是空切片")// arr是空切片 
}

2.2 下标创建切片

切片名 := 数组名[起始索引, 结束索引]

一旦这样声明,切片就会将数组 [****起始下标,结束下标​**)**中的值引用一份。

var arr [10]int = [10]int{1, 2, 3, 4, 5, 6, 7}
// slice就是一个切片,slice将 1~2 下标的值复制一份。
// 这个slice中的元素为: [2, 3]
var slice []int = arr[1:3]
  • 如果缺起始下标,默认从数组开头区域截取。

  • 如果缺结束下表,默认从截取至数组结束。

len(切片) :查看切片的大小

len(slice)

cap(切片) :查看切片的容量

cap(slice)
// 0 <= len(slice) <= cap(slice) <= len(arr)

看看切片地址与数组地址到底一样不一样 :

image

使用的下标必须是非负且在范围内的,若超过范围,会出现 panic

2.3 make创建切片

name := make(Type, length, capacity)

切片名 := make(切片类型,切片长度,切片长度)

// 定义一个切片,类型为int数组, 长度为5, 容量为20 
slice := make([]int, 5, 20)

该切片最大扩容到 长度 = 容量 = 20。

你是否会有疑惑,不是说切片是数组的引用,必须引用一个数组吗?

For example, make([]int, 0, 10) allocates an underlying array of size
and returns a slice of length and capacity that is backed by this underlying array

关于make的官方解释如上所示 :声明一个底层数组,返回关于这个数组的切片。 将数组隐藏起来,通过切片操作数组。

切片定义后跟正常的数组使用一样,可以通过 变量名[下标] 进行操作。

slice2 := make([]int, 5, 20)

fmt.Println(slice2) //此时为空切片
slice2[0] = 1
slice2[1] = 23
slice2[2] = 32
slice2[3] = 154
slice2[4] = 6
fmt.Println(slice2) //此时已经有值

3. 切片的底层

切片的底层是一个结构体,有三个变量 :指针​、长度​、容量

image

4. 切片的注意事项

  1. 切片可以继续切片,多个切片指向同一块区域,会互相影响。

  2. 切片不能直接比较,无法用 ==​​判断两个切片是否相等,它唯一的等值操作用于和 nil​​比较。

    一个nil的切片,底层指针是无指向的,并且长度、容量都为0。

    slice == nil

    len(slice) = 0

    cap(slice) = 0

    一个指向0数组的切片,底层是有指向的,长度、容量都为0

    slice != nil​​

    len(slice) = 0

    cap(slice) = 0

    所以不能使用 切片是否为nil 来判断切片是否为空,应该判断 len(切片) 是否为0

5. 切片的扩容和拷贝

上文说过,切片是对数组的引用,可以扩容,那么它是如何扩容的?切片会自动扩容吗?

尝试以下能否自动扩容 :

// 声明一个长度为5,容量为20的切片
slice2 := make([]int, 5, 20)

// 将前五个空间占满
slice2[0] = 1
slice2[1] = 23
slice2[2] = 32
slice2[3] = 154
slice2[4] = 6

// 给第六个空间赋值
slice2[5] = 6

发现运行出现bug,证明无法自动扩容。

那么该如何扩容 ?使用 append()

5.1 append()

func append (slice []Type, elems …Type) []Type

第一个参数是想要扩容的切片。

第二个参数是给这个切片扩容的元素,要与原切片中的元素类型相同。

返回值是扩容后的切片。

slice2 := make([]int, 5, 20)

slice2[0] = 1
slice2[1] = 23
slice2[2] = 32
slice2[3] = 154
slice2[4] = 6

// 这样是错误的: slice2[5] = 6
slice3 := append(slice2, 6)
fmt.Println(slice3)

这样就给切片扩容了一个元素 :6

切片的扩容策略 :

  • 如果新申请的容量(cap)大于2倍的旧容量(old.cap),最终的容量(newcap)就是新容量

  • 否则判断 旧容量(old.cap)的长度小于1024,如果小于,最终容量(newcap)就是旧容量(old.cap)的2倍

  • 如果大于等于1024,最终容量(newcap)从旧容量开始循环增加 (newcap + 256*3) / 4,直至最终容量(newcap)大于等于新容量(cap)

    注意 :循环增加多少,这个要看Go语言版本,不同版本可能不同。并且扩容规则针对不同类型也有不同的实现。

func growslice(et *_type, old slice, cap int) slice {
	// 此处省略一大段判断条件...
	newcap := old.cap
	doublecap := newcap + newcap
	if cap > doublecap {
		newcap = cap
	} else {
		const threshold = 256
		if old.cap < threshold {
			newcap = doublecap
		} else {
			for 0 < newcap && newcap < cap {
				newcap += (newcap + 3*threshold) / 4
			}
			if newcap <= 0 {
				newcap = cap
			}
		}
	}
	// 下面省略一大段判断条件
}

新申请的容量(cap)大于2倍的旧容量(old.cap)

slice2 := make([]int, 0, 1)

slice2 = append(slice2, 1, 2, 3, 4, 5, 6)

fmt.Println("slice2的长度为:", len(slice2))
fmt.Println("slice2的容量为:", cap(slice2))

image

容量小于1024,最终容量是旧容量的二倍

slice5 := make([]int, 0, 1)
for i := 0; i < 10; i++ {
	slice5 = append(slice5, i)
	fmt.Printf("切片的长度为: %d\t\t", len(slice5))
	fmt.Printf("切片的容量为: %d\n", cap(slice5))
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7rDoNM89-1673752243237)(null)]

累了,另外一个不想算了…🥲

5.2 copy()

当多个切片指向同一个数组时,它们操作共享空间,彼此影响。这时需要使用拷贝函数 copy() 对切片进行值拷贝。

func copy(dst, src []Type) int

dst :目标切片

src :数据来源切片

返回值 :拷贝了多少个数据过去

slice2 := make([]int, 5, 20)

slice2[0] = 1
slice2[1] = 23
slice2[2] = 32
slice2[3] = 154
slice2[4] = 6

slice4 := make([]int, 5, 5)

i := copy(slice4, slice2)

fmt.Println("copy的返回值为:", i) // 5
fmt.Println("slice4的值为:", slice4) // [1 23 32 154 6]

copy也被称为深拷贝,直接将一个切片指向另一个切片叫浅拷贝

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

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

相关文章

vite构建vue项目目录简介

文章目录1.项目目录介绍2.开发插件安装3.vue组件中的语法规范(SFC 语法规范)4.npm run dev命令执行过程1.项目目录介绍 public 下面的不会被编译 可以存放静态资源assets 下面可以存放可编译的静态资源components 下面用来存放我们的组件App.vue 是全局组件main ts 全局的ts文…

react基础Day01-React概述脚手架搭建JSX组件

React基础知识点 目标 能够说出React是什么能够说出React的特点能够掌握React的基本使用能够使用React脚手架 什么是React &#xff08;★★★&#xff09; React是一个用于构建用户界面的javaScript库&#xff0c;起源于facebook的内部项目&#xff0c;后续在13年开源了出…

Mysql入门技能树-时间日期函数(二)-练习篇

EXTRACT 关于 Extract 操作和其它日期时间函数的对应关系&#xff0c;下列说法正确的是&#xff1a; 1.extract(mirosecond from date) 相当于 ms(date) 2.extract(second from date) 相当于 second(date) 3.extract(minute from date) 相当于 minute(date) 4.extract(hour f…

IO流(二)

1.对象流-ObjectInputStream和ObjectOutputStream&#xff08;处理流包装流&#xff09;的基本原理 看一个需求&#xff1a; 1.将int num100这个int数据保存到文件中&#xff0c;注意不是100数字&#xff0c;而是int 100,并且&#xff0c;能够从文件中直接恢复int 100 2.将Dog …

Excel工具类实现——基于poi5.2.3

初衷仅是因为网上的Excel工具类不是太老旧的方法&#xff0c;就是不是很满足我想法&#xff0c;就想要自己搞一个&#xff0c;不过还不支持合并单元格等复杂的操作&#xff0c;后续看看能不能优化&#xff0c;有大神有更好的方法&#xff0c;可以公众号联系我&#xff0c;让我学…

基于jsp+mysql+Spring的SpringBoot美容院预约管理系统设计和实现

基于jspmysqlSpring的SpringBoot美容院预约管理系统设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文…

编制万年历的历程

初入编程之道的学子大都试编过万年历。万年历有二种&#xff1a;一为只有西历的月历&#xff0c;另一为有农历对照的月历或日历。编写万年历程序可以练练手&#xff0c;加深对编程语言的理解。记得我初入此道是在1994年&#xff0c;我那时刚买了486电脑&#xff0c;也刚开始有视…

概率论基本概念

全概率公式 P(B)P(BA1)P(BA2)...P(BAn) P(B) P(B|A1)P(A1) P(B|A2)P(A2) ... P(B|An)P(An)P(BA1)P(BA2)...P(BAn) 事件A1&#xff0c;A2&#xff0c;…构成一个完备事件组且都有正概率 某一个事件概率 这个事件*其他完备事件划分联合概率之和 联合概率 联合概率指的…

线程安全问题(2)

锁的相关知识&#xff1a; 1)这就是类似于说我们ATM机上面有一把锁&#xff0c;同一时刻&#xff0c;如果说人们之间不相互认识&#xff0c;那么通过这把锁就进行限制了说就限制了说一次只能有一个人来进来取钱&#xff0c;我们通过这样的锁&#xff0c;就可以来进行避免上述这…

ESP8266 Arduino开发 搭建web服务器与客户端开发

一、wifi 相关配置 1.1 无线终端 wifi 模式 此模式中&#xff0c;esp8266 会连接到指定 wifi 进行工作。 #include <ESP8266WiFi.h> // 本程序使用ESP8266WiFi库const char* ssid "home"; // 连接WiFi名&#xff08;此处使用home为示例&…

位运算相关

1.与运算 &#xff08;点我&#xff09; 这个题的大概意思&#xff1a;给222个数nnn和xxx&#xff0c;其中满足n&(n1)&(n2)&(n3)...&mxn\&(n1)\&(n2)\&(n3)...\&mxn&(n1)&(n2)&(n3)...&mx,求最小的mmm&#xff0c;只要满足m&g…

【异常】java11提示: Cannot find any provider supporting RSA/ECB/PKCS1Padding的问题

一、背景 项目中需要对敏感字段进行加密&#xff0c;但是加密方法中涉及到比较复杂的加密算法&#xff0c;这些算法都需要一个Provider&#xff0c;主要是用于初始化算法的。 以下是遇到的具体问题 二、报错截图 java.security.NoSuchAlgorithmException: Cannot find any pr…

【软件测试】软件测试模型

1. V模型 需求分析—计划—设计—编码—测试 ● 概要设计&#xff1a;设计整体架构&#xff0c;框架 ● 详细设计&#xff1a;模块和模块之间的详细设计 ● 集成测试&#xff0c;单元测试&#xff1a;通常由开发人员进行 特点&#xff1a; 明确标注了测试的多类型明确标注了测…

Introduction to Multi-Armed Bandits——01 Scope and Motivation

Introduction to Multi-Armed Bandits——01 Scope and Motivation 参考资料 Slivkins A. Introduction to multi-armed bandits[J]. Foundations and Trends in Machine Learning, 2019, 12(1-2): 1-286.项目地址 https://github.com/yijunquan-afk/bandit-learning Bandit…

LeetCode622.设计循环队列

设计循环队列1.题目描述2.思路3.代码实现以及分析3.1 创建结构体3.2创建一个具体的循环队列3.3判断是否为空 和 判断是否为满4. 进队列 和 出队列5.取队首和队尾元素6.释放空间7.总结1.题目描述 设计循环队列 2.思路 环形队列的抽象图 我们这里使用数组模拟实现循环队列&…

TransactionTemplate自动注入,只看这一篇文章就够了

标准的springboot接入mybatis步骤 1.引入了对应的依赖包 2.应用的properties下增加相应配置 3.根据配置进行自动装配 一般我们会配置这些信息&#xff0c;主要包括三类 1.数据库的连接信息 2.指定的数据源类型 3.mybatis的配置信息 配完以后&#xff0c;当你启动SpringBoot的主…

你是真的“C”——详解C语言数组模块知识

详解C语言数组模块知识&#x1f60e;前言&#x1f64c;一维数组的创建和初始化&#x1f64c;1.1 数组的创建&#x1f49e;1.2 数组的初始化&#x1f49e;1.3 一维数组的使用&#x1f49e;1.4 一维数组在内存中的存储&#x1f49e;二维数组的创建和初始化&#x1f64c;1.1 二维数…

【Python百日进阶-数据分析】Day225 - plotly的Ohlc图go.Ohlc()

文章目录一、语法二、参数三、返回值四、实例4.1 简单的OHLC图4.2 隐藏滑块的OHLC图4.3 添加自定义文本和注释4.4 自定义OHLC颜色4.5 带日期时间对象的简单的OHLC图4.6 自定义悬浮文本4.7 Dash中的应用一、语法 ohlc&#xff08;Open-High-Low-Close 的缩写&#xff09;是一种…

【C++逆向】虚表(Virtual table)逆向 | 安卓so虚函数逆向

什么是多态 定义一个虚基类ISpeaker class ISpeaker{ protected:size_t b; public:ISpeaker( size_t _v ): b(_v) {}virtual void speak() 0; };有两个子类&#xff0c;都实现了虚函数speak()&#xff1a; class Dog : public ISpeaker { public:Dog(): ISpeaker(0){}//vir…

1581_AURIX_TC275_SMU故障处理梳理

全部学习汇总&#xff1a; GreyZhang/g_TC275: happy hacking for TC275! (github.com) 前面为了缓解自己的学习压力&#xff0c;一次学习笔记大概也就是看10页文档整理一下。这一次其实是看了几十页&#xff0c;但是里面过掉了一些信息&#xff0c;而且这部分内容不是很好拆分…