切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。
切片是一个引用类型,它的内部结构包含地址
、长度
和容量
。切片一般用于快速地操作一块数据集合。
数组和切片的区别
数组:[n]int
切片:[ ]int
// 定义切片并且初始化
s1 := []string{"上海", "呼市", "包头"} //切片
s3 := []int{1, 3, 5, 7, 9}
s2 := [3]string{"上海", "呼市", "包头"} //数组
fmt.Printf("%T\n", s2)
fmt.Printf("%T\n", s1)
fmt.Printf("%T\n", s3)
fmt.Println(s1 == nil)
fmt.Println(s3 == nil)
fmt.Printf("s1的长度:%d,s1的容量:%d\n", len(s1), cap(s1))
fmt.Printf("s3的长度:%d,s3的容量:%d\n", len(s3), cap(s3))
切片:指向底层数组。
切片的长度就是它元素的个数
切片的容量是底层数组从切片的第一个元素到最后一个元素的数量;
通过代码理解:
// 由数组得到切片
d1 := [...]int{1, 3, 5, 7, 9, 11, 13}
fmt.Printf("%T\n", d1)
d2 := d1[0:4] //基于一个数组切割,左包含右不包含=>左闭右开
fmt.Println(d2)
d3 := d1[2:5]
fmt.Println(d3)
d4 := d1[3:]
fmt.Println(d4)
d5 := d1[:]
fmt.Println(d5)
fmt.Printf("%T\n", d5)
// 切片的长度就是元素的个数
// 切片的容量是底层数组的容量,从切片开始的下标指向数组的最后一个下表才是切片容量
fmt.Printf("d2的长度:%d,d2的容量:%d\n", len(d2), cap(d2))
fmt.Printf("d3的长度:%d,d3的容量:%d\n", len(d3), cap(d3))
切片是一个引用类型,都指向底层数组,底层数组的值发生变化切片也会改变
//切片再切割
d6 := d4[3:]
fmt.Printf("d6的长度:%d,d6的容量:%d\n", len(d6), cap(d6))
fmt.Println("d6", d6)
//切片是一个引用类型,都指向了底层的一个数组。
d1[6] = 88
fmt.Println("d4", d4)
fmt.Println("d6", d6)
d4[3] = 99
fmt.Println("d4", d4)
fmt.Println("d6", d6)
make()可以动态的创建切片
s1 := make([]int, 5, 10)
fmt.Printf("s1=%v len(s1)=%d cap(s1):%d\n", s1, len(s1), cap(s1))
s2 := make([]int, 0, 10)
fmt.Printf("s2=%v len(s2)=%d cap(s2):%d", s2, len(s2), cap(s2))
fmt.Println()
//切片的赋值
s3 := []int{1, 3, 5}
s4 := s3
fmt.Println(s3, s4)
s3[0] = 100
fmt.Println(s3, s4)
//切片遍历
//1、索引遍历
for i := 0; i < len(s3); i++ {
fmt.Println(s3[i])
}
//2、for range 循环遍历
for i, v := range s3 {
fmt.Println(i, v)
}
Go语言的内建函数append()
可以为切片动态添加元素。 可以一次添加一个元素,可以添加多个元素,也可以添加另一个切片中的元素(后面加…)。
s1 := []string{"北京", "上海", "广州"}
fmt.Printf("s1=%v,len(s1)=%d,cap(s1)=%d\n", s1, len(s1), cap(s1))
// s1[4] = "呼市" //错误写法,会导致编译报错:索引越界
//调用append函数必须用原来的切片变量接收返回值
//append追加元素,原来的底层数组放不下的时候,Go底层就会把底层数组换一个
//必须用原来变量接收append的返回值
s1 = append(s1, "深圳")
fmt.Printf("s1=%v,len(s1)=%d,cap(s1)=%d\n", s1, len(s1), cap(s1))
s1 = append(s1, "杭州", "成都")
fmt.Printf("s1=%v,len(s1)=%d,cap(s1)=%d\n", s1, len(s1), cap(s1))
ss := []string{"武汉", "西安", "苏州"}
s1 = append(s1, ss...)
fmt.Printf("s1=%v,len(s1)=%d,cap(s1)=%d\n", s1, len(s1), cap(s1))
//关于append删除某个切片中的某个元素
a1 := [...]int{1, 3, 5, 7, 9, 11, 13, 15, 17}
d1 := a1[:]
//删掉索引为1,2,3的三个数
d1 = append(d1[:1], d1[4:]...)
fmt.Println(d1)
fmt.Println(a1)
a1 := []int{1, 3, 5}
a2 := a1 //赋值
a3 := make([]int, 3, 5)
copy(a3, a1) //a1来源切片,a3目标切片
fmt.Println(a1, a2, a3)
a1[0] = 100
fmt.Println(a1, a2, a3)
//将a1中索引为1的3这个元素删掉
a1 = append(a1[:1], a1[2:]...)
fmt.Println(a1)
fmt.Println(cap(a1))
x1 := [...]int{1, 3, 5} //数组
s1 := x1[:] //切片
fmt.Println(s1, len(s1), cap(s1))
//1、切片不保存具体的值
//2、切片对应一个底层数组
//3、底层数组都是占用一块连续的内存
fmt.Printf("%p\n", &s1[1])
s1 = append(s1[:1], s1[2:]...) //修改了底层数组
fmt.Printf("%p\n", &s1[1])
fmt.Println(s1, len(s1), cap(s1))
fmt.Println(x1)