vector
切片有些类似于其他语言中的数组,但是有一些不同寻常的特性。
因为数组的长度是固定的并且数组长度属于类型的一部分,所以数组有很多的局限性。
1.1 切片的声明
两种声明切片类型的语句:
第一种
var sliceName []V
//其中 sliceName 是变量名
//V 表示切片中元素的类型
第二种
make()
func main() {
// 声明切片类型
var a []string //声明一个字符串切片
var b = []int{} //声明一个整型切片并初始化
//使用make()
var slice2 []int = make([]int, 5, 7) //长度为5 ,容器最大的容量是7的切片,变量名是slice2
}
两种声明方法的对比
make()make()gcmake()
1.2 切片的长度和容量
len()cap()
由于切片的底层就是一个数组,所以我们可以基于数组定义切片。
注意:切片的截取是左闭右开的。(什么是左闭右开?见下c和d)
func main() {
// 基于数组定义切片
a := [5]int{1,2,3,4,5}
//把b声明为从a种第一个元素到第四个元素的新切片。
b := a[1:4] //基于数组a创建切片,包括元素a[1],a[2],a[3]
fmt.Println(b) //[56 57 58]
fmt.Printf("type of b:%T\n", b) //type of b:[]int
}
/* 还支持如下方式:
c := a[1:] //[2 3 4 5]
d := a[:4] //[1 2 3 4]
e := a[:] //[1 2 3 4 5]
*/
2 Go语言中切片类型出现的原因
切片是一种数据类型,这种数据类型便于使用和管理数据集合。
创建一个100万个int类型元素的数组,并将它传递给函数,将会发生什么?
一道面试真题
func main() {
s := []int{1, 2, 3}
ss := s[1:]
ss = append(ss, 4)
for _, v := range ss {
v += 10
}
for i := range ss {
ss[i] += 10
}
fmt.Println(s) //
}
2.1 切片的结构
首先我们需要明白切片的结构。slice在Go的运行时库中就是一个C语言动态数组的实现。
type slice struct {
ptr *array //底层存储数组
len int //当前存储了多少个元素
cap int //底层数组可以存储多少个元素(从ptr指向的位置开始)
}
这个结构有3个字段,第一个字段表示array的指针,就是真实数据的指针(这个一定要注意),第二个是表示slice的长度,第三个是表示slice的容量,特别需要注意的是:
1.slice的长度和容量都不是指针
2.切片操作并不复制切片指向的元素。它创建一个新的切片并复用原来切片的底层数组。
切片操作并不复制切片指向的元素。它创建一个新的切片并复用原来切片的底层数组。 使得切片操作和数组索引一样高效。因此,通过一个新切片修改元素会影响到原始切片的对应元素。
切片的本质
a := [8]int{0, 1, 2, 3, 4, 5, 6, 7}s1 := a[:5]
3 切片不能直接比较
nilnilnil0nil
var s1 []int //len(s1)=0;cap(s1)=0;s1==nil
s2 := []int{} //len(s2)=0;cap(s2)=0;s2!=nil
s3 := make([]int, 0) //len(s3)=0;cap(s3)=0;s3!=nil
len(s) == 0s == nil
4 切片的赋值拷贝
下面的代码中演示了拷贝前后两个变量共享底层数组,对一个切片的修改会影响另一个切片的内容,这点需要特别注意。
func main() {
s1 := make([]int, 3) //[0 0 0]
s2 := s1 //将s1直接赋值给s2,s1和s2共用一个底层数组
s2[0] = 100
fmt.Println(s1) //[100 0 0]
fmt.Println(s2) //[100 0 0]
}
5 切片遍历
for range
func main() {
s := []int{1, 3, 5}
for i := 0; i < len(s); i++ {
fmt.Println(i, s[i])
}
for index, value := range s {
fmt.Println(index, value)
}
}
6 append()
append()append()append
举个例子:
func main() {
//append()添加元素和切片扩容
var numSlice []int
for i := 0; i < 10; i++ {
numSlice = append(numSlice, i)
fmt.Printf("%v len:%d cap:%d ptr:%p\n", numSlice, len(numSlice), cap(numSlice), numSlice)
}
}
7 copy()
问题:
func main() {
a := []int{1, 2, 3, 4, 5}
b := a
fmt.Println(a) //[1 2 3 4 5]
fmt.Println(b) //[1 2 3 4 5]
b[0] = 1000
fmt.Println(a) //[1000 2 3 4 5]
fmt.Println(b) //[1000 2 3 4 5]
}
abba
copy()copy()
copy(destSlice, srcSlice []T)
// srcSlice: 数据来源切片
// destSlice: 目标切片
简单的例子:
func main() {
// copy()复制切片
a := []int{1, 2, 3, 4, 5}
c := make([]int, 5, 5)
copy(c, a) //使用copy()函数将切片a中的元素复制到切片c
fmt.Println(a) //[1 2 3 4 5]
fmt.Println(c) //[1 2 3 4 5]
c[0] = 1000
fmt.Println(a) //[1 2 3 4 5]
fmt.Println(c) //[1000 2 3 4 5]
}
8 删除元素
使用切片本身的特性来删除元素。
func main() {
// 从切片中删除元素
a := []int{30, 31, 32, 33, 34, 35, 36, 37}
// 要删除索引为2的元素
a = append(a[:2], a[3:]...)
fmt.Println(a) //[30 31 33 34 35 36 37]
}
aindexa = append(a[:index], a[index+1:]...)