Go 数组和切片反思

news2024/11/16 9:32:50

切片的底层数据结构是数组,所以,切片是基于数组的上层封装,使用数组的场景,也完全可以使用切片。

类型比较

我看到 go 1.17 有对切片和数组转换的优化,禁不住纳闷,有什么场景是必须数组来完成的呢?我特意去查了一下数组和切片的核心差异,刨去有的没的,核心就 2 点:

  • 数组是可比较的,切片是不可比较的,验证的方式也非常简单。声明一个 map 类型,如果 key 的类型是切片,会报如下的编译错误。如果是数组类型,可以正常编译。
  • 数组赋值是值拷贝,切片赋值是引用拷贝,切片类型在值拷贝前后,底层共用的还是同一个数组,而数组的值拷贝就是值拷贝。

在这里插入图片描述
在查看的过程中,我也有发现数组指针的用法,除了可以通过数组本身来操作数组,还可以通过数组指针来操作。而这种使用手法,是切片不具备的。

下面的代码,通过数组指针 (&b) 可以像直接使用 b 一样访问数组的元素,而通过使用指针赋值的方式,也可以让两个变量共用同一个数组。

func main() {
	var b = [3]int{11, 12, 13} //
	fmt.Println((&b)[0])
	fmt.Println(b[0])
}

下面数组的赋值过程, a 和 b 是值拷贝,完全独立的两份数据,b 数组修改第一个元素,并不会影响到数组 a。而 c 和 a 是数组指针类型的值拷贝,共享同一份数组数据,c 数组修改第一个元素,也就修改了 a 指向的数组。

func main() {
	var a = [3]int{11, 12, 13} //

	b := a
	b[0] = 10
	fmt.Println(a[0])
	fmt.Println(b[0])

	c := &a
	c[0] = 10
	fmt.Println(a[0])
	fmt.Println(c[0])
}

类型转换

数组和切片的转换,说实话,在业务开发的过程中,我基本上没有用到这种转换场景。因为切片的底层是数组,数组可以直接转换为切片类型,转换后,切片和数组共享同一份空间。

func main() {
	var a = [3]int{11, 12, 13} 

	b := a[:len(a)]

	fmt.Printf("%T,%T", b, a)
}

仔细想想,切片在 go 中的结构为 SliceHeader ,除了数组 Data 部分,还包含了 Len 和 Cap 两个属性。所以,go 数组转切片的过程,也是封装这个 SliceHeader 的过程。

type SliceHeader struct {
	Data uintptr
	Len  int
	Cap  int
}

但在 1.17 之前,切片是不能直接转换为数组的,要想转换为数组,就需要通过 unsafe 包来实现。不过,切片要转换为数组,相比,数组转换为切片,要简单很多。

原理上就是获取切片底层数组的第一个元素的指针,转换为数组的指针。

func main() {
	var a = []int{11, 12, 13} //
	b := (*[3]int)(unsafe.Pointer(&a[0]))
	fmt.Println(b)
}

现在 go 1.17 默认也支持了这个转换,转换的方式也很好理解,转换为数组类型的指针。因为是指针,所以,转换后的数组 b 和 a 仍然还是共用同一份数据。

为什么默认转换使用的类型是数组指针 (*[3]int),而非 ([3]int) 呢?我理解,如果是值类型的话,还需要底层数据的拷贝,语义上也没有指针类型好理解。

func main() {
	var a = []int{11, 12, 13} //
	b := (*[3]int)(a)
	fmt.Println(b)
}

应用

结合以往的工作,比较适合使用数组替代切片的场景大概就是:控制并发的顺序。

我们有一组数组 reqs,要请求某一个接口。然后,需要按照请求的顺序,返回请求的结果。我们使用 go 协程并发请求接口,然后基于请求的索引,将接口返回的结果存储到对应索引数组的位置。

因为数组的个数是固定的,所以,这种场景还是比较少的


func main() {

	var reqs [3]interface{} = [...]interface{}{1, 2, 3}
	var res [3]interface{}

	for i:= range reqs {
		go func(index int) {
			res[index] = reqs[index]
		}(i)
	}

	time.Sleep(time.Second)
	fmt.Println(res)
}

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

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

相关文章

vue项目第七天

项目中模块操做业务使用ajax(需要使用接口认证)修改封装的findData发送ajax请求管理员列表内部搜索业务复用之前的findData 方法即可实现整个查询业务。实现退出业务在下拉菜单上添加事件以及属性。用户退出登录,二次登录系统菜单可能不存在的…

linux环境搭建私有gitlab仓库

搭建之前,需要安装相应的依赖包,并且要启动sshd服务(1).安装policycoreutils-python openssh-server openssh-clients [rootVM-0-2-centos ~]# sudo yum install -y curl policycoreutils-python openssh-server openssh-clients [rootVM-0-2-centos ~]…

(API)接口测试的关键技术

接口测试也就是API测试,从名字上可以知道是面向接口的测试活动。所以在讲API测试之前,我们应该说清楚接口是什么,那么接口就是有特定输入和特定输出的一套逻辑处理单元,而对于接口调用方来说,不用知道自身的内部实现逻…

Spring 中经典的 9 种设计模式

1.简单工厂(非23种设计模式中的一种) 2.工厂方法 3.单例模式 4.适配器模式 5.装饰器模式 6.代理模式 7.观察者模式 8.策略模式 9.模版方法模式 Spring中涉及的设计模式总结 1.简单工厂(非23种设计模式中的一种) 实现方式: BeanFactory。Spring中的BeanFa…

Android 初代 K-V 存储框架 SharedPreferences,旧时代的余晖?

本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问。 前言 大家好,我是小彭。 SharedPreferences 是 Android 平台上轻量级的 K-V 存储框架,亦是初代 K-V 存储框架,至今被很多应用沿用。 有的…

【C语言】大小端字节序问题

一、大小端字节序问题 大小端是由CPU决定的,大小端可以理解为字节顺序,所以大小端全称叫大端字节序、小端字节序。其实大端、小端这两个词是从《格列佛游记》里出来的。《格列佛游记》有一段讲的是吃鸡蛋是从大的那头敲开还是小的那头敲开的问题&#xf…

拯救了大批爬虫程序员,因为一个简单的神器

相信大家应该都写过爬虫,简单的爬虫只需要使用 requests 即可。遇到复杂的爬虫,就需要在程序里面加上请求头和参数信息。类似这种:我们一般的步骤是,先到浏览器的网络请求中找到我们需要的请求,然后将请求头和参数信息…

CI/CD --- 什么才是真正的自动化平台

近2年在软件开发中比较火的两个术语,一个是敏捷开发,另外一个就是CI/CD了;敏捷开发顾名思义就是“以用户的需求进化为核心,采用迭代、循序渐进的方法进行软件开发”。那CI/CD(Continuous Integration、 Continuous Del…

自抗扰控制ADRC之微分器TD

目录 前言 1 全程快速微分器 1.1仿真分析 1.2仿真模型 1.3仿真结果 1.4结论 2 Levant微分器 2.1仿真分析 2.2仿真模型 2.3仿真结果 3.总结 前言 工程上信号的微分是难以得到的,所以本文采用微分器实现带有噪声的信号及其微分信号提取,从而实现…

0216-0218复习:继承

目录 继承 一、基本介绍 二、示意图 三、基本语法 四、入门案例 父类 子类1 子类2 main方法 五、继承细节 第一条 第二条 第三条 第四条 ​编辑 第五条 第六条 第七条 第八条 第九条 第十条 六、继承本质 七、练习题 第三题 继承 一、基本介绍 继承可以…

RAY - 小记

文章目录关于 RAYRAY 结构关于 RAY Ray is a unified framework for scaling AI and Python applications. Ray consists of a core distributed runtime and a toolkit of libraries (Ray AIR) for accelerating ML workloads. RAY 是一个简单、通用的分布式计算框架。 RAY 解…

TikTok话题量超30亿,这款承载美好记忆的剪贴簿引发讨论

回忆风剪贴簿在TikTok引起关注小超在浏览超店有数后台时发现,有一款平平无奇的剪贴簿的种草视频爆火,在24h内收获了9.9K点赞,播放量更是突破了100W,直接冲到了【种草视频飙升榜】第六名的位置,并且这个数字目前仍在继续…

利用5G工业网关实现工业数字化的工业互联网解决方案

5G工业网关是一种用于将工业生产环境中的数据连接到工业互联网的解决方案。它可以利用高带宽、高速率、低时延的5G网络连接工业现场的PLC、传感器、工业设备和云端数据中心,从而实现工业数字化。 物通博联工业互联网解决方案 物通博联5G工业网关的使用步骤&#x…

XXL-JOB分布式任务调度框架(二)-策略详解

文章目录1.引言2.任务详解2.1.执行器2.2.基础配置3.路由策略(第一个)-案例4.路由策略(最后一个)-案例5.轮询策略-案例6.随机选取7.轮询选取8.一致性hash9.最不经常使用 (LFU)10.最近最久未使用(LRU)11.故障转移12.忙碌转移7.分片广播任务1.引言 本篇文章…

中外互免签证协定一览表(普通护照与公务普通护照)

普通护照:由公安部出入境管理机构或者公安部委托的县级以上地方人民政府公安机关出入境管理机构以及中华人民共和国驻外使馆、领馆和外交部委托的其他驻外机构签发,主要颁发给出国定居、探亲、访友、继承财产、留学、就业、旅游等因私事出国的中国公民。…

[REDIS]redis的一些配置文件

修改配置文件 vim /etc/redis/redis.conf目录 protected-mode tcp-backlog timeout tcp-keepalive daemonize pidfile loglevel databases 设置密码 maxclients maxmemory maxmemory-policy maxmemory-samples 默认情况下 bind127.0.0.1 只能接受本机的访问请求。在不写的情况…

算法导论【字符串匹配】—朴素算法、Rabin-Karp、有限自动机、KMP

算法导论【字符串匹配】—朴素算法、Rabin Karp、有限自动机、KMP朴素字符串匹配算法Rabin-Karp算法有限自动机KMP算法朴素字符串匹配算法 预处理时间:0匹配时间:O((n-m1)m) Rabin-Karp算法 预处理时间:Θ(m),需要预先算出匹…

Lua脚本执行redis指令报错【java.lang.IllegalStateException】

Lua脚本执行redis指令报错【java.lang.IllegalStateException】 问题出现背景 今天在学习redis时,为了让redis的多条指令(取锁、比锁、释放锁)保障原子性,我通过使用一个lua脚本统一去执行redis的的多条指令。在执行lua脚本时报错…

Python3 File(文件) 方法讲解

open() 方法 Python open() 方法用于打开1个文件,并返回文件对象。 在对文件进行处理过程都需要使用到这个函数,如果这个文件无法被打开,会抛出 OSError。 注意:使用 open() 方法一定要保证关闭文件对象,即调用 clo…

vrrp+mstp+osfp经典部署案例

LSW1和LSW2和LSW3和LSW4上面启用vrrpmstp组网: vlan 10 全走LSW1出再走AR2到外网,vlan 20 全走LSW2出再走AR3到外网 配置注意:mstp实例的根桥在哪,vrrp的主设备就是谁 ar2和ar3上开nat ar2和ar3可以考虑换成两台防火墙来做&…