切片(Slice)是一个拥有相同类型元素的可变长度的序列。它底层是一个数组。它很灵活,可以自动扩容。
切片是一个引用类型,它的内部结构包含地址、长度和容量。切片一般用于快速地操作一块数据集合。
用make函数构造切片
make([]T,size,cap) T:切片里元素的类型 size:元素的数量(长度) cap:容量
func main() {
a := make([]int, 2, 10)
fmt.Println(a) //[0 0]
fmt.Println(len(a)) //2
fmt.Println(cap(a)) //10
}
上面的代码中a相当于make在底层分配了10个大小的内存,也就是它的底层数组长度为10([0,0,0,0,0,0,0,0,0,0]),但是只给你显示出来2个长度
切片的本质
其实它就是对底层数组的封装,显示它规定的数组内容,通过指针指向底层数组位置;就比如说一个数组a:=[8]int{0,1,2,3,4,5,6,7},切片s1:=a[:5]则当我们打印s1时,就是[0,1,2,3,4];s2:=a[2:6],则s1打印出来就是[2,3,4,5];(左包含右不包含)
图片来自七米老师,供大家理解
切片值操作问题
两个切片是不能进行比较的,唯一合法的比较就是和nil进行比较
前面说过切片是一个引用类型,当使用切片a2=a1时,这时a2和a1是同时指向同一底层数组的,当修改a1的值时,a2的值也会变,因为他们指向同一个数组。如果你想他们互不干扰就可以用copy()函数,先用make函数初始化a2,使其拥有自己的一块内存,自己的一个底层数组,再用copy(a2,a1)就可以了
func main() {
// copy()复制切片
a1 := []int{1, 2, 3, 4, 5}
a2 := make([]int, 5, 5)
copy(a2, a1) //使用copy()函数将切片a1中的元素复制到切片a2
fmt.Println(a1) //[1 2 3 4 5]
fmt.Println(a2) //[1 2 3 4 5]
a2[0] = 1000
fmt.Println(a1) //[1 2 3 4 5]
fmt.Println(a2) //[1000 2 3 4 5]
}
append 方法
用append时要注意其append出来的新切片所指向的数组与原来的切片指向的数组是不一样的,执行这个方法时相当于使用了make重新分配了一片内存
func main(){
var s []int
s1 := append(s, 1) // [1]
s1 = append(s1, 2, 3, 4) // [1 2 3 4]
s2 := append(s1, 5) // [1 2 3 4 5]
s2[0] = 5
fmt.Println(s1) // [1 2 3 4]
fmt.Println(s2) // [5 2 3 4 5]
}
切片是会自动扩容,具体有自己的一套扩容机制,所以我们一般不需要担心切片大小的问题
本篇文章是通过参考七米老师的博客整理的,其中有一些自己的理解,具体参考七米老师的博客:www.liwenzhou.com/posts/Go/06…