GO语言-Slice切片

前言

切片Slice,与数组相似。也叫变长数组或者动态数组。特点:变长。

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关键字创建slice

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))
}

slice赋值操作对底层数组的影响

  1. 对array元素操作时,所有指向array的slice的元素也会发生改变。
  2. 对slice中元素操作时,实际时对array的元素进行操作。
  3. slice发生扩容时,实际是开辟了新的内存空间,所以原来的array不会发生改变。

具体示例 

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)
}

 GO语言-Slice切片_第1张图片

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)
}

GO语言-Slice切片_第2张图片

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)
}

GO语言-Slice切片_第3张图片

append插入元素

语法

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...)

切片Slice内存分析

  查看内存地址的时候。数值类型,如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.因为扩容要改变底层数组,所以底层数组的内存地址发生了改变;如果不需要扩容,内存地址就不会发生改变。 

你可能感兴趣的:(Golang,golang,开发语言,后端)