1. 切片是什么?
在Go语言中,切片(slice)是一种动态数组,可以伸缩的序列。它由指向数组某个元素的指针、切片长度和切片容量组成。我们可以使用内置函数 make 来创建切片。切片的语法和数组很像,但是它比数组更加灵活。
1.1 切片的语法
切片的声明和数组类似,只是没有长度。
var a []int // 声明一个切片
使用内置函数 make 来创建切片,并指定长度和容量。
a := make([]int, 5) // 长度为5,容量为5
切片的语法中可以使用冒号分割切片的开始和结束位置。
a := []int{1, 2, 3, 4, 5} // 声明一个切片并赋值
b := a[1:3] // 从切片a中取出元素索引为1和2的元素,构成新的切片b
需要注意的是,切片不会拷贝底层数组,它只是对底层数组的引用。
1.2 切片的长度和容量
切片的长度表示其中元素的个数,可以使用内置函数 len 来获取切片的长度。
a := []int{1, 2, 3, 4, 5}
len := len(a) // 获取切片a的长度,结果为5
切片的容量表示其中可以存储的元素个数,可以使用内置函数 cap 来获取切片的容量。
a := make([]int, 5, 10) // 创建切片,长度为5,容量为10
cap := cap(a) // 获取切片a的容量,结果为10
1.3 切片与底层数组
切片是对底层数组的一个引用,改变切片中元素的值会影响到底层数组,而且多个切片可以共享同一个底层数组。
a := []int{1, 2, 3, 4, 5} // 声明一个切片并赋值
b := a[1:3] // 从切片a中取出元素索引为1和2的元素,构成新的切片b
b[0] = 6 // 修改切片b第一个元素的值为6
fmt.Println(a) // [1 6 3 4 5]
fmt.Println(b) // [6 3]
2. 切片的操作
2.1 中间添加元素
我们可以使用内置函数 append 来在切片的中间或末尾添加元素。
a := []int{1, 2, 3, 4, 5} // 声明一个切片并赋值
b := append(a[:2], 6) // 在切片a中索引为0和1之间添加元素6,并赋值给切片b
fmt.Println(a) // [1 2 6 4 5]
fmt.Println(b) // [1 2 6]
2.2 中间删除元素
我们可以使用切片的语法特性,将一个切片复制自己的一部分,来删除中间的元素。
a := []int{1, 2, 3, 4, 5} // 声明一个切片并赋值
a = append(a[:2], a[3:]...) // 删除切片a中索引为2的元素,并赋值给切片a
fmt.Println(a) // [1 2 4 5]
3. 切片的性能
切片在底层是一个指向底层数组的指针、切片长度和容量,通过这三个属性,Go语言可以自动伸缩切片。但是切片的自动伸缩也会带来性能问题。
比如,如果我们在一个长度为100的切片中添加元素,其底层数组可能不够用,需要重新分配更大的内存空间,然后复制原数组到新数组中,这个过程需要耗费时间。所以,在性能敏感的场合,应该尽量避免切片的自动伸缩。
针对切片的性能问题,我们可以使用内置函数 make 在声明的时候就为切片创建足够的空间,从而避免切片自动扩容而带来的性能影响。
4. 总结
切片是Go语言中非常重要的一种数据结构,它通过动态数组的形式实现了变长数组的功能,并且支持多个切片引用同一个底层数组。但是,由于切片底层是数组,所以容易引发内存泄露等性能问题,需要注意。