7.Go语言中的slice

Go语言中的slice,又称切片,比较类似动态数组,类似Java中的List,slice支持自动扩容,是常用的数据接口之一。

在了解slice之前,先介绍下,Go中的数组,数组是长度固定且类型相同的连续序列,有三个重要特征,(1)长度固定(2)元素类型相同(3)连续序列,长度相同和元素类型相同的2个数组可以称为这两个数组类型是一样的,连续序列指的是在内存中数组占用的是一段连续的内存。

Go中的数组是值类型的,所以在将数组传递进函数时,会发生值拷贝,即深拷贝一份数组给函数的形参,如果数据较大,会带来一定的性能问题,比较常见的做法是使用指针,在Go中更建议使用slice来代替数组的使用。

切片对于数组就像文件描述符对于文件,数组通常作为slice的底层存储存在,slice也可以看作是数组的窗口,使用slice屏蔽了底层数组的操作和扩容等,是非常常用的数据结构。

slice由三部分构成:(1)指向第一个元素的指针(2)长度(3)容量

这也就意味着slice是一个轻量级的,在传参时值拷贝也只是拷贝一个指针,slice的长度指的是开在数组上的窗口的大小,slice的容量指的是在底层数组上,从指针位置到数组末尾的大小。

下面的代码展示了切片的定义方式:(1)直接创建切片,runtime会在底层帮构建数组

(2)在已有的数组上切片化,切片上也可以切片化,此时会存在多个切片共享一个底层数组。

slice的自动扩容机制可以查看 $GOROOT/src/runtime/slice.go中的growslice函数

slice在自动扩容时会新建一个新的数组,然后将老数组的元素复制到新数组中,注意的是不会将老的slice指向这个新的数组,这和Java中的ArrayList的实现机制不同,所以在使用Go中的slice时,在append操作时,需要使用原有的slice变量接收下append的结果,否则发生自动扩容后,slice变量绑定的还是老的数组。

Go 复制代码
package main

import "fmt"

func main() {
	// 1 数组是固定长度 且 类型相同的连续序列
	// 因此 数组类型有2个属性:元素类型 和 数组长度
	// 只有 元素类型 和 长度 都相同的数组才能称之为同类型的数组
	// go语言的数组是值类型的,所以在传递数组到函数内时,发生的是值拷贝,如果数组比较大会有性能问题
	// 比较常见的做法是 将数组传递给函数的时候,传指针,但是在go中建议的做法是使用切片

	// 2 切片对于数组 就像 文件描述符对于文件
	// slice由三个结构构成,分别是 指针array 长度len 容量cap
	// array: 指向底层数组某元素的指针,该元素是切片的起始元素
	// len: 切片的长度,即切片中的元素个数
	// cap: 切片的最大容量

	// 3 直接创建切片,会在底层创建一个数组,数组的长度为5
	s := make([]byte, 5)
	fmt.Printf("s = %v\n", s)

	// 4 通过数组的 切片化 构造切片
	// 注意 当从一个数组上 切片化出多个切片时,切片对数组的修改是可能会影响其他切片的
	u := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	us1 := u[3:7]
	fmt.Printf("us1 = %v\n", us1)

	// 5 切片的动态扩容
	var s1 []int
	fmt.Printf("len = %v, cap = %v\n", len(s1), cap(s1)) // len = 0, cap = 0
	s1 = append(s1, 11)
	fmt.Printf("len = %v, cap = %v\n", len(s1), cap(s1)) // len = 1, cap = 4
	s1 = append(s1, 12)
	fmt.Printf("len = %v, cap = %v\n", len(s1), cap(s1)) // len = 2, cap = 4
	s1 = append(s1, 13)
	fmt.Printf("len = %v, cap = %v\n", len(s1), cap(s1)) // len = 3, cap = 4
	s1 = append(s1, 14)
	fmt.Printf("len = %v, cap = %v\n", len(s1), cap(s1)) // len = 4, cap = 4
	s1 = append(s1, 15)
	fmt.Printf("len = %v, cap = %v\n", len(s1), cap(s1)) // len = 5, cap = 8
}
相关推荐
L.EscaRC2 小时前
深度解析 Spring 框架核心代理组件 MethodProxy.java
java·开发语言·spring
逍遥德2 小时前
函数式编程 Java Lambda Stream及其实现类常用函数
java·后端·spring
2501_941982052 小时前
Java 分布式环境下的 Access_Token 一致性方案:如何避免多节点冲突?
java·开发语言·分布式
chilavert3182 小时前
技术演进中的开发沉思-328 JVM:垃圾回收(上)
java·开发语言·jvm
qq_397562312 小时前
Qt_工程执行逻辑_窗口逻辑
开发语言·qt
hoiii1872 小时前
基于MATLAB的Kriging代理模型实现与优化
开发语言·matlab
火云洞红孩儿2 小时前
2026年,用PyMe可视化编程重塑Python学习
开发语言·python·学习
2501_944521592 小时前
Flutter for OpenHarmony 微动漫App实战:标签筛选功能实现
android·开发语言·前端·javascript·flutter
阿蒙Amon2 小时前
C#每日面试题-索引器和迭代器的区别
开发语言·windows·c#