切片Slice,与数组相似。也叫变长数组或者动态数组。特点:变长。
Slice是一个引用类型的容器,指向了一个底层数组。
var slice_name []type
slice_name := []type{v1, v2, v3, v4}
//切片名 := 数组[开始下标, 结束下标] 注意:不包含结束下标
slice_name := array_name[start:end]
func main() {
arr := [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
slice_test1 := arr[1:4] //2-4
slice_test2 := arr[:5] //1-5
slice_test3 := arr[5:] //6-9
slice_test4 := arr[:] //1-9
fmt.Println(slice_test1)
fmt.Println(slice_test2)
fmt.Println(slice_test3)
fmt.Println(slice_test4)
}
make关键字专门用于创建引用类型的数据。
语法
make(type, size1, size2)
第一个参数是类型 slice、map、chan
第二个参数是长度
第三个参数是容量。
存储长度超过容量时,会自动扩容。
默认存储数据,int类型时使用0填充;string类型时使用空字符串填充。可以通过下标操作默认已存在的值。
func main() {
slice_test1 := make([]int, 3, 5)
fmt.Printf("slice_test1: %v; slice长度: %v; slice容量: %v\n", slice_test1, len(slice_test1), cap(slice_test1))
//append元素,超过slice容量
slice_test1 = append(slice_test1, 1, 2, 3)
fmt.Println("---append后---")
fmt.Printf("slice_test1: %v; slice长度: %v; slice容量: %v\n", slice_test1, len(slice_test1), cap(slice_test1))
}
具体示例
1.当底层数组改变时,所有指向这个array的slice响应索引位置上的值也会发生改变。
func main() {
arr := [6]int{1, 2, 3, 4, 5, 6}
slice_test1 := arr[:]
slice_test2 := arr[:3]
slice_test3 := arr[3:]
fmt.Println("slice_test1:", slice_test1)
fmt.Println("slice_test2:", slice_test2)
fmt.Println("slice_test3:", slice_test3)
arr[1] += 1
arr[4] += 1
fmt.Println("---对array元素操作后---")
fmt.Println("slice_test1:", slice_test1)
fmt.Println("slice_test2:", slice_test2)
fmt.Println("slice_test3:", slice_test3)
}
2.当操作slice内容时,比如从slice[index]修改索引位置上的值或者使用append新增值时,都是对底层数组进行操作。所以同(1),其他指向这个array的slice对应的位置也会发生改变。
func main() {
arr := [6]int{1, 2, 3, 4, 5, 6}
slice_test1 := arr[:]
slice_test2 := arr[:3]
slice_test3 := arr[3:]
fmt.Println("slice_test1:", slice_test1)
fmt.Println("slice_test2:", slice_test2)
fmt.Println("slice_test3:", slice_test3)
slice_test1[1] += 1
slice_test1[4] += 1
fmt.Println("---对slice元素操作后---")
fmt.Println("slice_test1:", slice_test1)
fmt.Println("slice_test2:", slice_test2)
fmt.Println("slice_test3:", slice_test3)
}
3.当使用append给slice增加值,操作slice容量,slice发生扩容。slice扩容时,会开辟新的内存地址。将原有的array内的值复制过来;进行扩容后再加入新的值。所以扩容情况下所新增的值不会对原有的array进行操作。
所以slice发生扩容时,只有被扩容的slice内的值发生变化。array不会发生变化,其他指向原有array的slice中的值也不会发生变化。
func main() {
arr := [6]int{1, 2, 3, 4, 5, 6}
slice_test1 := arr[:]
slice_test2 := arr[:3]
slice_test3 := arr[3:]
fmt.Printf("slice_test1: %v; slice_test1长度: %v; slice_test1容量: %v \n", slice_test1, len(slice_test1), cap(slice_test1))
fmt.Println("slice_test2:", slice_test2)
fmt.Println("slice_test3:", slice_test3)
slice_test1 = append(slice_test1, 7, 8, 9)
slice_test1[1] += 1
slice_test1[4] += 1
fmt.Println("---slice_test1发生扩容时---")
fmt.Println("原数组arr:", arr)
fmt.Println("slice_test1:", slice_test1)
fmt.Println("slice_test2:", slice_test2)
fmt.Println("slice_test3:", slice_test3)
}
语法
slice_name = append(slice_name, v1, v2)
slice_name = append(slice_name, slicename2...)
可以把slice_name2切片的值全部插入slice_name中。但是slice_name2后面必须有三个点,表示时切片。
func main() {
slice_test1 := []int{1, 2, 3}
slice_test2 := []int{4, 5, 6}
fmt.Println("append前slice_test1:", slice_test1)
slice_test1 = append(slice_test1, slice_test2...)
fmt.Println("appendslice_test2后slice_test1:", slice_test1)
slice_test1 = append(slice_test1, 7, 8, 9)
fmt.Println("append单个元素后slice_test1:", slice_test1)
}
浅拷贝: slice1 := slice2
深拷贝: slice1 := append([]int{}, slice2...)
查看内存地址的时候。数值类型,如array、int等,fmt.Printf(%p\n, &arr) ,要再变量前加上&符号;引用类型,如slice,fmt.Printf(%p\n, slice1) ,不需要加&符号。
func main() {
s1 := []int{1, 2, 3, 4}
fmt.Println(s1)
fmt.Printf("s1的地址: %p; s1的长度: %v; s1的容量: %v \n", s1, len(s1), cap(s1))
s1 = append(s1, 5, 6)
fmt.Println(s1)
fmt.Printf("s1的地址: %p; s1的长度: %v; s1的容量: %v \n", s1, len(s1), cap(s1))
}
1.创建数组s1时,是先创建一个底层数组。然后再用切片s1指向底层数组。此时长度和容量一样。
2.切片本身不存储数据,都是底层数组存储数据。所以修改也是修改底层数组。
3.扩容:底层数组扩容时,其容量都是成倍扩容的。所以使用append操作切片,发生扩容时,slice的容量也是成倍扩容。
4.因为扩容要改变底层数组,所以底层数组的内存地址发生了改变;如果不需要扩容,内存地址就不会发生改变。