Go 语言函数式编程系列教程(十) —— 数据类型篇:在数组切片中动态增删元素

栏目: Go · 发布时间: 5年前

内容简介:切片比数组更强大之处在于支持动态增加元素,甚至可以在容量不足的情况下自动扩容,关于容量我们在上篇教程中已经简单提及过,在切片类型中,元素个数和实际可分配的存储空间是两个不同的值,元素的个数即切片的实际长度,而可分配的存储空间就是切片的容量。一个切片的容量初始值根据创建方式的不同而不同:所以,通常一个切片的长度值小于等于其容量值,我们可以通过 Go 语言内置的

动态增加元素

切片比数组更强大之处在于支持动态增加元素,甚至可以在容量不足的情况下自动扩容,关于容量我们在上篇教程中已经简单提及过,在切片类型中,元素个数和实际可分配的存储空间是两个不同的值,元素的个数即切片的实际长度,而可分配的存储空间就是切片的容量。

一个切片的容量初始值根据创建方式的不同而不同:

make

所以,通常一个切片的长度值小于等于其容量值,我们可以通过 Go 语言内置的 cap() 函数和 len() 函数来获取某个切片的容量和实际长度:

var oldSlice = make([]int, 5, 10)

fmt.Println("len(oldSlice):", len(oldSlice))
fmt.Println("cap(oldSlice):", cap(oldSlice))

程序运行结果如下:

len(oldSlice): 5
cap(oldSlice): 10

此时,切片 oldSlice 的默认值是 [0 0 0 0 0] ,我们可以通过 append() 函数向切片追加新元素:

newSlice := append(oldSlice, 1, 2, 3)

将返回的新切片赋值给 newSlice ,此时 newSlice 的长度是 8,容量是 10,切片值是:

[0 0 0 0 0 1 2 3]

函数 append() 的第二个参数是一个不定参数,我们可以按自己需求添加若干个元素(大于等于1个),甚至直接将一个数组切片追加到另一个数组切片的末尾:

appendSlice := []int{1, 2, 3, 4, 5}
newSlice := append(oldSlice, appendSlice...)  // 注意末尾的 ... 不能省略

如果追加的元素个数超出 oldSlice 的默认容量,则底层会自动进行扩容:

newSlice := append(oldSlice, 1, 2, 3, 4, 5, 6)
fmt.Println(newSlice)
fmt.Println(len(newSlice))
fmt.Println(cap(newSlice))

此时 newSlice 的长度变成了 11,容量变成了 20,需要注意的是 append() 函数并不会改变原来的切片,而是会生成一个容量更大的切片,然后把原有的元素和新元素一并拷贝到新切片中,默认情况下,扩容后新切片的容量将会是原切片容量的 2 倍,如果还不足以容纳新元素,则按照同样的操作继续扩容,直到新容量不小于原长度与要追加的元素数量之和。但是,当原切片的长度大于或等于 1024 时,Go 语言将会以原容量的 1.25 倍作为新容量的基准。

因此,如果实现能预估切片的容量并在初始化时合理地设置容量值,可以大幅降低切片内部重新分配内存和搬送内存块的操作次数,从而提高程序性能。

内容复制

切片类型还支持 Go 语言的另一个内置函数 copy() ,用于将元素从一个数组切片复制到另一个数组切片。如果加入的两个数组切片不一样大,就会按其中较小的那个数组切片的元素个数进行复制。下面的示例展示了 copy() 函数的行为:

slice1 := []int{1, 2, 3, 4, 5} 
slice2 := []int{5, 4, 3}

// 复制 slice1 到 slice 2
copy(slice2, slice1) // 只会复制 slice1 的前3个元素到 slice2 中
// 复制 slice2 到 slice 1
copy(slice1, slice2) // 只会复制 slice2 的 3 个元素到 slice1 的前 3 个位置

动态删除元素

切片除了支持动态增加元素之外,还可以动态删除元素,在切片中动态删除元素可以通过多种方式实现(其实是通过切片实现的「伪删除」):

slice3 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
slice3 = slice3[:len(slice3) - 5]  // 删除 slice3 尾部5个元素
slice3 = slice3[5:]  // 删除 slice3 头部 5 个元素

此时切片 slice3 的所有元素被删除,长度是0,容量也变成 5,注意这里不是自动缩容,而是第二个切片容量计算逻辑决定的。

此外,还可以通过上述介绍的 append 函数和 copy 函数实现切片元素的「删除」:

slice3 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

slice4 := append(slice3[:0], slice3[3:]...)  // 删除开头三个元素
slice5 := append(slice3[:1], slice3[4:]...)  // 删除中间三个元素
slice6 := append(slice3[:0], slice3[:7]...)  // 删除最后三个元素

slice7 := slice3[:copy(slice3, slice3[3:])]  // 删除开头前三个元素

append 相对好理解一些, copy 之所以可以用于删除元素,是因为其返回值是拷贝成功的元素个数,我们可以根据这个值完成新切片的设置从而达到「删除」元素的效果。

和动态增加元素一样,原切片的值并没有变动,而是创建出一个新的内存空间来存放新切片并将其赋值给其它变量。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

奇点系列

奇点系列

彼得•蒂尔、里德•霍夫曼、本•霍洛维茨、埃里克•杰克逊等 / 高玉芳、路蒙佳、杨晓红、徐彬等 / 中信出版社 / 2015-6-20 / 182.00

1.硅谷创投教父、PayPal创始人彼得•蒂尔、LinkedIn创始人里德•霍夫曼、创业导师本•霍洛维茨、“PayPal黑帮”初创成员埃里克•杰克逊联合作品。 2.彼得•蒂尔与埃隆•马斯克的首次交锋,PayPal从0到1改变全球金融的生死突围,商业硬汉的创业史诗,揭秘“PayPal黑帮”的创业维艰与联盟关系。 3.《人民日报》推荐创业者必读书目!“奇点系列”的作者们以及“PayPal黑......一起来看看 《奇点系列》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

html转js在线工具
html转js在线工具

html转js在线工具