Slice
切片的概念
Go 语言切片是对数组的抽象。
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大
切片是一种方便、灵活且强大的包装器。切片本身没有任何数据。它们只是对现有数组的引用。
切片与数组相比,不需要设定长度,在[]中不用设定值,相对来说比较自由
从概念上面来说slice像一个结构体,这个结构体包含了三个元素:
-
指针,指向数组中slice指定的开始位置
-
长度,即slice的长度
-
最大长度,也就是slice开始位置到数组的最后位置的长度
总而言之,有点像集合,也有点像指针(有一点吧,我觉得,像集合是因为它是动态的,长度可变的,像指针是因为切片可以指向数组的地址,可能不太对嗷)
切片的语法
切片的创建
直接创建
方法一:
就像定义数组一样,但是不用填入长度
var identifier []type
方法二:
使用make()函数来创建:
make([]T, length, capacity)
//例如
s:=make([]int,3,9)
T是类型,length是长度,capacity是容量(长度是下限,容量是上限)
fmt.Println("len:",len(s),"cap:",cap(s))
通过数组创建切片
例如
//使用数组a,创建切片
a := [10]int{1,2,3,4,5,6}
s1 := a[:4] //s1中的数据为:1~5
s2 := a[1:3] //s2中的数据为:2~4
s3 := a[:] //s3中的数据为:1~6(全部数据)
//这个时候,切片指向的数组为a,切片中的元素改变,它所指向的数组中的元素也改变
//但是如果切片进行扩容,并且扩容后长度大于指向的数组,切片指向的数组就会改变(原因参考下文“切片的扩容”)
初始化
var s = []int{1, 2, 3}
切片的扩容
当切片中的元素饱和时,使用append函数可以扩充切片
例如
//原本长度为0
s:=make([]int,0,4)
//使用append函数后增加了两个元素
s = append(s,1,2)
也可以把另一个切片中的元素全部添加到切片中
例如
s:=append(s2,s3...)//使用...表示添加的时切片
切片的内存分析(建立)
当扩容时,如果扩容后的切片长度大于切片给的容量,这个时候是改变了切片对应的底层数组(切片是引用类型)而且每扩容一次,容量变为原来的两倍(例如长度为2,扩容后长度为4)
例如
s := []int{1,2,3}
fmt.Printf("切片指向的数组的地址是,%p",s)
fmt.Println()
fmt.Printf("切片自身的地址是,%p",&s)
切片的遍历
和数组一样
例如
for i:=0;i<len(s);i++{
fmt.Println(s4[i])
}
//或者使用range
for _,v:=range s{
fmt.Println(v)
}
复制切片
使用copy函数
简单用法如下文代码所示
//将s中的元素复制到s1里
copy(s1,s)
也可以选择拷贝的位置
例如
//从s1切片的第二位元素开始接收复制的元素
copy(s1[1;],s)
//从s切片的第3位开始复制给s1
copy(s1,s[2:])