这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战
切片slice
这是我第一次接触到这个概念, 当时很好奇, 这倒底是什么容器类型
切片大家完全可以理解为一个动态数组
切片是一个引用类型, 所以切片变量是一个指针
切片有长度和容量的概念
长度就是它当前实际上存储的元素数量
容量是这个切片所能存储的最大元素的数量
所以长度永远不会大于容量
在Go中切片比数组更常用哦
定义一个切片
切片不需要指定长度, 因为它是动态的
格式: var xxx []type
定义一个空切片
/*
输出:
[]int(nil)
s0的容量: 0
s0的长度: 0
*/
var s0 []int
fmt.Printf("%#v\n", s0)
fmt.Println("s0的容量: ", cap(s0))
fmt.Println("s0的长度: ", len(s0))
数组的方式来创建切片
// 用定义数组的方式, 定义一个切片
// 从定义方式来看,切片就是一个不指定长度的数组
s1 := []int {1, 3, 5}
fmt.Printf("%#v\n", s1)
用make来创建切片
/*
创建一个容量为5, 长度为3的int类型的切片
*/
s2 := make([]int, 3, 5)
fmt.Printf("%#v\n", s2)
fmt.Println("s2的容量: ", cap(s2))
fmt.Println("s2的长度: ", len(s2))
/*
容量为可靠参数, 我们可以只传长度
*/
s3 := make([]int, 3)
fmt.Println("s3的容量: ", cap(s3))
fmt.Println("s3的长度: ", len(s3))
通过数组生成一个切片
slice := array[start:end:max] array为目标数组 start: 表示从这个下标开始, 包括这个位置的元素 end: 表示到这个下标结束, 不包括这个位置的元素 max-start: 表示容量
// 从数组中生成一个切片
arr := [5]int {1, 2, 3, 4, 5}
s4 := arr[1:3:5]
fmt.Printf("%#v\n", s4)
fmt.Println("s4的容量: ", cap(s4))
fmt.Println("s4的长度: ", len(s4))
通过切片生成另一个切片
/*
输出
s6的容量: 10
s6的长度: 6
*/
s5 := make([]int, 5, 10)
s6 := s5[:6]
fmt.Printf("%#v\n", s5)
fmt.Println("s6的容量: ", cap(s6))
fmt.Println("s6的长度: ", len(s6))
切片重组 reslicing
通过改变切片长度得到新的切片的过程, 称为切片重组 新的切片会继续引用原有切片的数组, 造成内存溢出
s7 := getSlice()
fmt.Println(cap(s7), len(s7), &s7[0])
func getSlice() []byte {
bytes := make([]byte, 100)
fmt.Println(cap(bytes), len(bytes), &bytes[0])
return bytes[:3]
}
copy函数
/*
通过copy函数来生成一个新的切片, 这个切片指向一个新的数组
*/
s8 := getSlice2()
fmt.Println(cap(s8), len(s8), &s8[0])
func getSlice2() []byte {
bytes := make([]byte, 100)
fmt.Println(cap(bytes), len(bytes), &bytes[0])
res := make([]byte, 3)
copy(res, bytes[:3])
return res
}
append函数
// 拼接单个元素
s9 := []int {1, 2, 3}
s10 := append(s9, 4, 5, 6)
fmt.Println(s10)
// 拼接切片中的某些元素
s11 := []int {1, 3, 5}
s12 := []int {2, 4, 6}
s13 := append(s11[1:3], s12[:2]...)
fmt.Println(s13)
// 拼接切片中的所有元素
s14 := append(s11, s12...)
fmt.Println(s14)
不同切片指向的数组
s15 := []int {1, 2, 3, 4, 5, 6}
s16 := s15[:3]
// 现在两个切片指向同一个数组
fmt.Println("第一个切片: ", s15, "切片地址: ", &s15[0])
fmt.Println("第二个切片: ", s16, "切片地址: ", &s16[0])
// 更改第二个切片的值
s16[0] = 7
s16[1] = 8
// 两个切片还是指向同一个数组
fmt.Println("第一个切片: ", s15, "切片地址: ", &s15[0])
fmt.Println("第二个切片: ", s16, "切片地址: ", &s16[0])
// 当数组的容量, 不能保证切片的操作时, append函数会再申请一个新的数组
s16 = append(s16, 10, 11, 12, 13)
fmt.Println("第一个切片: ", s15, "切片地址: ", &s15[0])
fmt.Println("第二个切片: ", s16, "切片地址: ", &s16[0])
fmt.Println(s15, s16)
总结
初识切片, 不知所措. 深入了解, 倍加喜爱. 切片真的的超级灵活, 超级好用. 当然在使用的过程, 大家要避免一些坑哦, 比如: 切片的重组, 以及在同一个数组上的不同切片的使用. 其它都很nice的!!!