切片Slice

116 阅读2分钟

切片(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];(左包含右不包含)

image.png

图片来自七米老师,供大家理解

切片值操作问题

两个切片是不能进行比较的,唯一合法的比较就是和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…