因为在Golang中,数组的长度是固定的,一旦定义,在后续的操作中就不能更改长度,在某些实际使用场景中就不是那么的的方便,这个时候我们就可以使用切片(slice)类型。
1. slice基本定义
地址长度容量
使用上来说 slice 是一个拥有相同类型元素的可变长度的序列,具有灵活、可自动扩容等优点。
本质上,slice 是一个指向 array 的指针,当拷贝 slice 给另一个变量时,两个引用会指向同一个 array,类似Python中的深拷贝,从任何一个变量里修改,其他变量包括底层数组都会跟着改变。
相关的操作如下所示:
// 定义一个切片
var s1 []int // 定义一个存放int类型元素的切片
var s2 []string // 定义一个存放string类型的切片
fmt.Println(s1, s2)
fmt.Println(s1 == nil) // nil 就是 null
fmt.Println(s2 == nil) // nil 就是 null
// 初始化
s1 = []int{1, 2, 3, 4}
s2 = []string{"北京", "上海"}
fmt.Println(s1, s2)
fmt.Println(s1 == nil) // nil 就是 null
fmt.Println(s2 == nil) // nil 就是 null
// 切片的长度和容量 len cap
fmt.Printf("len(s1):%d cap(s1):%d\n", len(s1), cap(s1))
fmt.Printf("len(s2):%d cap(s2):%d\n", len(s2), cap(s2))
// 由数组得到切片
a := [...]int{1, 3, 5, 7, 11, 13, 17, 19}
s3 := a[0:5]
s4 := a[1:4]
s5 := a[3:]
fmt.Println(s3)
fmt.Println(s4)
fmt.Println(s5)
// 切片的容量是指底层数组从切片开始的第一个元素到最后元素的数量
fmt.Printf("len(s3):%d cap(s3):%d\n", len(s3), cap(s3))
fmt.Printf("len(s4):%d cap(s4):%d\n", len(s4), cap(s4))
fmt.Printf("len(s5):%d cap(s5):%d\n", len(s5), cap(s5))
// 切片的拷贝是深拷贝
s6 := s3
s3[1] = 200
s6[0] = 100
fmt.Printf("\n修改后的a:%d\n", a)
fmt.Printf("修改后的s3:%d\n", s3)
fmt.Printf("修改后的s6:%d\n", s6)
/*slice是引用类型,本质上是一个指向array的指针,当拷贝slice给另一个变量时,两个引用会指向同一个array*/
// 切片之后再切片
s7 := s3[2:]
fmt.Println("\ns3:", s3)
fmt.Println("s7:", s7)
fmt.Printf("len(s3):%d cap(s3):%d\n", len(s3), cap(s3))
fmt.Printf("len(s7):%d cap(s7):%d\n", len(s7), cap(s7)) // 切割两次之后仍然是以最开始的数组作为底层数组
make([]int, 10, 100)
====nilnilnil
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
2. slice的相关操作
append
append()
var b = make([]int, 0, 2)
fmt.Println(b)
fmt.Printf("len(b): %d cap(b): %d\n\n", len(b), cap(b))
b = append(b, 1, 2, 3)
fmt.Println(b)
fmt.Printf("len(b): %d cap(b): %d\n\n", len(b), cap(b))
b = append(b, 4, 5)
fmt.Println(b)
fmt.Printf("len(b): %d cap(b): %d\n\n", len(b), cap(b))
b = append(b, 6, 7)
fmt.Println(b)
fmt.Printf("len(b): %d cap(b): %d\n", len(b), cap(b))
b = append(b, 8, 9, 10, 11, 12, 13)
fmt.Println(b)
fmt.Printf("len(b): %d cap(b): %d\n", len(b), cap(b))
运行结果:
此外,当新增的内容,超出原slice的容量,则slice会依照下面的策略进行扩容,原文来自
李文周的博客
intstring
使用append可以删除slice中指定索引的元素,例如:
// 使用append删除slice中的某个元素
a1 := [...]int{2, 3, 5, 7, 11, 13, 17}
s1 := a1[:]
// 删除s1中索引为1的元素3
s1 = append(s1[:1], s1[2:]...)
fmt.Println(s1)
fmt.Println(a1) // 底层的数组也会将那个值删掉,并往后补上最后的元素的值
...
a := []int{1, 2, 3}
b := []int{4, 5, 6}
a = append(a, b...) //a = [1 2 3 4 5 6]