Golang切片slice

切片可以简单的理解为可以动态扩展的数组。

由于数组创建后长度就不能再修改了,所以golang就定义了slice,它的长度可以扩展,我们先来看一下slice源码的结构。

type slice struct {
	array unsafe.Pointer
	len   int
	cap   int
}

可以看到有一个指针,其作用还是指向一个数组,所以说,slice底层还是应用在了数组这个数据结构之上。

len是切片实际使用长度,也就是实际存储元素所占用的存储空间。

cap是总占用空间,也就是切片预先申请的一段空间的总容量。

切片的定义:

通过make函数来创建切片

package main

import "fmt"

func main() {
	ints1 := make([]int, 10, 20)
	fmt.Printf("切片len:%v,切片cap:%v \n",len(ints1),cap(ints1))

	ints2 := make([]int, 10)
	fmt.Printf("切片len:%v,切片cap:%v \n",len(ints2),cap(ints2))
}

输出结果:

切片len:10,切片cap:20 
切片len:10,切片cap:10 

第一个make,有三个参数,第二个指定了len的长度,第三个指定了cap的长度。

第二个make,只有两个参数,如果不指定cap,默认len和cap相等。

也可以将len指定为0,当使用slice时,会自动扩展长度。

ints3 := make([]int, 0)
mt.Printf("切片len:%v,切片cap:%v \n",len(ints3),cap(ints3))

//输出结果
切片len:0,切片cap:0 

除了用make方式创建切片,还可以用已定义的数组来创建。

arr1 := [10]int{1,2,3,4,5,6}
sli1 := arr1[0:4]
fmt.Println("切片sli1:",sli1)

输出结果:

切片sli1: [1 2 3 4]

这里arr1[0:4],相当于就是从下标0开始,取4个元素,也就是取到数组的下标3的元素,0,1,2,3这4个元素,其实你可以直接用4-0=4,就知道了这个表达式要取4个元素。

截取的表达式还可以省略开头或结尾的数字,省略开头表示从开头第一个元素开始截取,省略结尾表示截取到最后一个元素,看deom

arr1 := [10]int{1,2,3,4,5,6}
sli1 := arr1[0:4]
sli2 := arr1[:4]
sli3 := arr1[0:]
fmt.Println("切片sli1:",sli1)
fmt.Println("切片sli2:",sli2)
fmt.Println("切片sli3:",sli3)

输出结果:

切片sli1: [1 2 3 4]
切片sli2: [1 2 3 4]
切片sli3: [1 2 3 4 5 6 0 0 0 0]

重点看这里:

sli2 := arr1[:4] 这是从头开始截取
sli3 := arr1[0:] 这是截取到末尾

切片支持的操作:

len()

cap()

append()

copy()

上面的demo已经演示了len()和cap()的使用。

append()表示在切片末尾追加元素。

copy()用来复制切片。

//append
sli3 = append(sli3, 77)
fmt.Println("切片sli3 append后的值:",sli3)
fmt.Printf("切片sli3 append后的len:%v,cap:%v",len(sli3),cap(sli3))

输出结果:

切片sli3 append后的值: [1 2 3 4 5 6 0 0 0 0 77]
切片sli3 append后的len:11,cap:20

这里需要注意的是,77被追加到了切片的下标为11的位置。

还要注意的是,切片的len是11,cap是20,说明切片扩容了,在golang中不同类型的扩容比例是不同的,int类型每次扩容是当前容量乘以2.

//copy
sli4 := make([]int, 20)
copy(sli4, sli3)
fmt.Println("sli4:",sli4)
fmt.Printf("%p \n",sli3)
fmt.Printf("%p \n",sli4)

输出结果:

sli4: [1 2 3 4 5 6 0 0 0 0 77 0 0 0 0 0 0 0 0 0]
0xc000098000 
0xc0000980a0 

我把完整demo代码贴出来。

package main

import "fmt"

/**
	www.itzhimei.com
 */
func main() {
	ints1 := make([]int, 10, 20)
	fmt.Printf("切片len:%v,切片cap:%v \n",len(ints1),cap(ints1))

	ints2 := make([]int, 10)
	fmt.Printf("切片len:%v,切片cap:%v \n",len(ints2),cap(ints2))

	ints3 := make([]int, 0)
	fmt.Printf("切片len:%v,切片cap:%v \n",len(ints3),cap(ints3))

	arr1 := [10]int{1,2,3,4,5,6}
	sli1 := arr1[0:4]
	sli2 := arr1[:4]
	sli3 := arr1[0:]
	fmt.Println("切片sli1:",sli1)
	fmt.Println("切片sli2:",sli2)
	fmt.Println("切片sli3:",sli3)

	sli3 = append(sli3, 77)
	fmt.Println("切片sli3 append后的值:",sli3)
	fmt.Printf("切片sli3 append后的len:%v,cap:%v \n",len(sli3),cap(sli3))

	sli4 := make([]int, 20)
	copy(sli4, sli3)
	fmt.Println("sli4:",sli4)
	fmt.Printf("%p \n",sli3)
	fmt.Printf("%p \n",sli4)
}

输出结果:

切片len:10,切片cap:20 
切片len:10,切片cap:10 
切片len:0,切片cap:0 
切片sli1: [1 2 3 4]
切片sli2: [1 2 3 4]
切片sli3: [1 2 3 4 5 6 0 0 0 0]
切片sli3 append后的值: [1 2 3 4 5 6 0 0 0 0 77]
切片sli3 append后的len:11,cap:20 
sli4: [1 2 3 4 5 6 0 0 0 0 77 0 0 0 0 0 0 0 0 0]
0xc000098000 
0xc0000980a0