golang基础(15.数组切片增删)
动态增加元素切片比数组强大之处在于能够动态增加元素,甚至可以在容量不足的情况下自动扩容。元素个数和元素可以分配的空间是两个不同的值,元素个数是长度,元素可分配空间是容量。一个切片容量的初始值可以根据创建方式改变
- 对于基于数组和切片创建的切片而言,默认容量是从切片起始索引到对应底层数组的结尾索引;
- 对于通过内置 make 函数创建的切片而言,在没有指定容量参数的情况下,默认容量和切片长度一致。
函数append()可以为数组末尾增加参数。如果追加的元素个数超出 原切片的的默认容量,则底层会自动进行扩容:
package main
import "fmt"
func main() {
slice1 := make([]int, 4, 10)
fmt.Println(len(slice1))
fmt.Println(cap(slice1))
slice2 := append(slice1, 1, 2, 3)
fmt.Println(len(slice2)) // 长度7
fmt.Println(cap(slice2)) // 容量10
slice1 = append(slice1, slice2...)
fmt.Println(slice1)
fmt.Println(len(slice1)) // 长度11
fmt.Println(cap(slice1)) // 容量20
}
需要注意的是append方法并不会改变原来的切片,而是会生成一个新的容量 更大切片当中,将原有的元素和新增的元素一并拷贝到新的切片中一并放回。默认情况下,扩容后的`新切片是原切片容量的2倍`。如果还不足以容纳新元素则会再次进行扩容,直到新的容量足够容纳下所有的元素。但是,当原切片的长度大于或等于 `1024 `时,Go 语言将会以原容量的 `1.25 `倍作为新容量的基准。<br />因此在开发阶段我们应该合理地分配容量值,减少内部因扩容重新分配内存和搬送内存的操作次数,提高程序性能。
内容复制
go中拥有一个复制数组切片的函数copy,作用是讲一个数组切片的元素搬运到另一个数组切片。如果两个数组切片的元素个数不一致,会按其中较小的切片进行复制。
package main
import "fmt"
func main() {
slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{6, 7, 8}
// 复制slice1到slice2
//copy(slice2, slice1)
//fmt.Println(slice2) // 输出1,2,3
// 复制slice2到slice1
copy(slice1, slice2)
fmt.Println(slice1) // 输出6,7,8,4,5
}
动态删除元素
除了支持动态增加元素之外,还可以动态删除元素,在切片中动态删除元素可以通过多种方式实现(其实是通过切片重新赋值实现的「伪删除」):
package main
import "fmt"
func main() {
slice1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
slice1 = slice1[:len(slice1)-5] // 删除尾部的5个元素
fmt.Println(slice1)
slice1 = slice1[1:] // 删除头部的1个元素
fmt.Println(slice1)
}
此时删除后的切片并非原来的切片,而是内部新构建返回的一个切片数组。其容量基于新的计算逻辑来决定。此外,还可以通过上述介绍的 append 函数和 copy 函数实现切片元素的「删除」:
package main
import "fmt"
func main() {
slice1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
slice1 = slice1[:len(slice1)-5] // 删除尾部的5个元素
fmt.Println(slice1)
slice1 = slice1[1:] // 删除头部的1个元素
fmt.Println(slice1)
slice3 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
//slice4 := append(slice3[:0], slice3[3:]...) //删除开头三个元素
//fmt.Println(slice4)
//slice5 := append(slice3[:1], slice3[4:]...) // 删除中间三个元素
//fmt.Println(slice5)
//slice6 := append(slice3[:0], slice3[:7]...) // 删除最后三个元素
//fmt.Println(slice6)
slice7 := slice3[:copy(slice3, slice3[3:])] // 删除开头前三个元素
fmt.Println(slice7)
}
append 相对好理解一些,copy 之所以可以用于删除元素,是因为其返回值是拷贝成功的元素个数,我们可以根据这个值完成新切片的设置从而达到「删除」元素的效果。和动态增加元素一样,原切片的值并没有变动,而是创建出一个新的内存空间来存放新切片并将其赋值给其它变量。