Go语言中的Slice学习总结
来源:脚本之家
时间:2023-01-12 15:29:45 464浏览 收藏
亲爱的编程学习爱好者,如果你点开了这篇文章,说明你对《Go语言中的Slice学习总结》很感兴趣。本篇文章就来给大家详细解析一下,主要介绍一下语言Slice,希望所有认真读完的童鞋们,都有实质性的提高。
概念
Slice切片是对底层数组Array的封装,在内存中的存储本质就是数组,体现为连续的内存块,Go语言中的数组定义之后,长度就已经固定了,在使用过程中并不能改变其长度,而Slice就可以看做一个长度可变的数组进行使用,最为关键的,是数组在使用的过程中都是值传递,将一个数组赋值给一个新变量或作为方法参数传递时,是将源数组在内存中完全复制了一份,而不是引用源数组在内存中的地址,为了满足内存空间的复用和数组元素的值的一致性的应用需求,Slice出现了,每个Slice都是都源数组在内存中的地址的一个引用,源数组可以衍生出多个Slice,Slice也可以继续衍生Slice,而内存中,始终只有源数组,当然,也有例外,后边再说。
用法
1.Slice的定义
Slice可以通过两种方式定义,一种是从源数组中衍生,一种是通过make函数定义,本质上来说都一样,都是在内存中通过数组的初始化的方式开辟一块内存,将其划分为若干个小块用来存储数组元素,然后Slice就去引用整个或者局部数组元素。
直接初始化一个Slice:
复制代码 代码如下:
s := []int{1, 2, 3}
注意,这与初始化数组有一点点区别,有的同学认为这个写法是定义和初始化一个数组,事实上这个写法是现在内存中构建一个包括有3个元素的数组,然后将这个数组的应用赋值给s这个Slice,通过以下数组的定义进行区别:
复制代码 代码如下:
a := [3]int{1, 2, 3}
b := [...]int{1, 2, 3}
c := []int{1, 2, 3}
fmt.Println(cap(a), cap(b), cap(c))
a = append(a, 4)//Error:first argument to append must be slice; have [3]int
b = append(b, 4)//Errot:first argument to append must be slice; have [3]int
c = append(c, 4)//正常,说明变量c是Slice类型
可以看出,强调了数组定义的规则:长度和类型必须指定,若是根据实际元素个数自动计算数组长度,需要使用[...]定义,而不能只使用[]。
从数组中切片构建Slice:
复制代码 代码如下:
a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
s := a[2:8]
fmt.Println(s) //输出:[3 4 5 6 7 8]
定义一个数组a,截取下标为2到8之间部分(包括2不包括8),构建一个Slice。
通过make函数定义:
复制代码 代码如下:
s := make([]int, 10, 20)
fmt.Println(s) //输出:[0 0 0 0 0 0 0 0 0 0]
make函数第一个参数表示构建的数组的类型,第二个参数为数组的长度,第三个参数可选,是slice的容量,默认为第二个参数值。
2.Slice的长度和容量
Slice有两个比较混淆的概念,就是长度和容量,何谓长度?这个长度跟数组的长度是一个概念,即在内存中进行了初始化实际存在的元素的个数。何谓容量?如果通过make函数创建Slice的时候指定了容量参数,那内存管理器会根据指定的容量的值先划分一块内存空间,然后才在其中存放有数组元素,多余部分处于空闲状态,在Slice上追加元素的时候,首先会放到这块空闲的内存中,如果添加的参数个数超过了容量值,内存管理器会重新划分一块容量值为原容量值*2大小的内存空间,依次类推。这个机制的好处在能够提升运算性能,因为内存的重新划分会降低性能。
复制代码 代码如下:
a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
s := a[0:]
s = append(s, 11, 22, 33)
sa := a[2:7]
sb := sa[3:5]
fmt.Println(a, len(a), cap(a)) //输出:[1 2 3 4 5 6 7 8 9 0] 10 10
fmt.Println(s, len(s), cap(s)) //输出:[1 2 3 4 5 6 7 8 9 0 11 22 33] 13 20
fmt.Println(sa, len(sa), cap(sa)) //输出:[3 4 5 6 7] 5 8
fmt.Println(sb, len(sb), cap(sb)) //输出:[6 7] 2 5
可以看出,数组的len和cap是永远相等的,并且是在定义的时候就已经指定的,不能改变。切片s引用这个数组的全部元素,初始长度和容量都为10,继续追加3个元素后,其长度变为13容量为20,。切片sa截取下标2到7的数组片段,长度为5,容量为8,这个容量的改变规则为原容量值减掉起始下标,此时若追加元素,会覆盖掉原内存地址中存在的值。切片sb截取切片sa下标3到5的数组片段,注意,这里的下标指的是sa的下标,不是源数组的下标,长度为2,容量为8-3=5。
3.Slice是引用类型
上边已经提到过,Slice是对源数组的一个引用,改变Slice中的元素的值,实质上就是改变源数组的元素的值。
复制代码 代码如下:
a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
sa := a[2:7]
sa = append(sa, 100)
sb := sa[3:8]
sb[0] = 99
fmt.Println(a) //输出:[1 2 3 4 5 99 7 100 9 0]
fmt.Println(sa) //输出:[3 4 5 99 7 100]
fmt.Println(sb) //输出:[99 7 100 9 0]
可以看到,不管是append操作,还是赋值操作,都影响了源数组或者其他引用同一数组的Slice的元素。Slice进行数组引用的时候,其实是将指针指向了内存中具体元素的地址,如数组的内存地址,事实上是数组中第一个元素的内存地址,Slice也是如此。
复制代码 代码如下:
a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
sa := a[2:7]
sb := sa[3:8]
fmt.Printf("%p\n", sa) //输出:0xc084004290
fmt.Println(&a[2], &sa[0]) //输出:0xc084004290 0xc084004290
fmt.Printf("%p\n", sb) //输出:0xc0840042a8
fmt.Println(&a[5], &sb[0]) //输出:0xc0840042a8 0xc0840042a8
4.Slice引用传递发生“意外”
上边我们一直在说,Slice是引用类型,指向的都是内存中的同一块内存,不过在实际应用中,有的时候却会发生“意外”,这种情况只有在像切片append元素的时候出现,Slice的处理机制是这样的,当Slice的容量还有空闲的时候,append进来的元素会直接使用空闲的容量空间,但是一旦append进来的元素个数超过了原来指定容量值的时候,内存管理器就是重新开辟一个更大的内存空间,用于存储多出来的元素,并且会将原来的元素复制一份,放到这块新开辟的内存空间。
复制代码 代码如下:
a := []int{1, 2, 3, 4}
sa := a[1:3]
fmt.Printf("%p\n", sa) //输出:0xc0840046e0
sa = append(sa, 11, 22, 33)
fmt.Printf("%p\n", sa) //输出:0xc084003200
可以看到执行了append操作后,内存地址发生了变化,说明已经不是引用传递。
以上就是《Go语言中的Slice学习总结》的详细内容,更多关于golang的资料请关注golang学习网公众号!
-
210 收藏
-
321 收藏
-
283 收藏
-
316 收藏
-
358 收藏
-
114 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习
-
- 坚强的金鱼
- 好细啊,mark,感谢大佬的这篇博文,我会继续支持!
- 2023-04-15 07:37:22
-
- 孝顺的饼干
- 很有用,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢博主分享技术贴!
- 2023-04-01 02:07:25
-
- 超帅的小松鼠
- 这篇技术文章出现的刚刚好,好细啊,太给力了,已收藏,关注楼主了!希望楼主能多写Golang相关的文章。
- 2023-02-26 00:37:22
-
- 清脆的柠檬
- 这篇文章内容太及时了,细节满满,赞 👍👍,已加入收藏夹了,关注老哥了!希望老哥能多写Golang相关的文章。
- 2023-02-20 14:07:00
-
- 甜美的美女
- 这篇文章内容真及时,太全面了,赞 👍👍,mark,关注博主了!希望博主能多写Golang相关的文章。
- 2023-01-28 13:44:32
-
- 高兴的魔镜
- 受益颇多,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢老哥分享博文!
- 2023-01-15 11:29:39
-
- 文艺的西装
- 受益颇多,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢up主分享博文!
- 2023-01-13 18:45:12
-
- 辛勤的菠萝
- 这篇文章真及时,很详细,感谢大佬分享,已加入收藏夹了,关注作者大大了!希望作者大大能多写Golang相关的文章。
- 2023-01-13 03:55:31