内部实现
切片是基于数组实现的,它的底层是数组,它自己本身非常小,可以理解为对底层数组的抽象。因为基于数组实现,所以它的底层的内存是连续非配的,效率非常高,还可以通过索引获得数据,可以迭代以及垃圾回收优化的好处。
切片对象非常小,是因为它是只有3个字段的数据结构:一个是指向底层数组的指针,一个是切片的长度,一个是切片的容量。这3个字段,就是Go语言操作底层数组的元数据,有了它们,我们就可以任意的操作切片了。
声明初始化
1、使用内置函数make初始化,
slice:=make([]int,5)
//slice:=make([]int,5,10)
使用内置函数make初始化需要传入一个参数,指定其长度,例子中使用的参数5就为其长度,同时也是其切片的容量。我们也可单独设置其容量如注释部分。
2、直接初始化
slice:=[]int{1,2,3,4,5}
slice1:=[]int{4:2}//直接指定 第五个数为2,未指定值为0
切片之间的操作
切片另外一个用处比较多的创建是基于现有的数组或者切片创建。这就对于Java内置的函数一样很方便
slice := []int{1, 2, 3, 4, 5}
slice1 := slice[:]
slice2 := slice[0:]
slice3 := slice[:5]
slice4 := slice[1:3]
slice4[1] = 10
fmt.Println(slice1)
fmt.Println(slice2)
fmt.Println(slice3)
fmt.Println(slice4)
for i := 0; i < 4; i++ {
slice4 = append(slice4, 6)
fmt.Println(slice)
fmt.Println(slice4)
}
运行结果
[1 2 10 4 5]
[1 2 10 4 5]
[1 2 10 4 5]
[2 10]
[1 2 10 6 5]
[2 10 6]
[1 2 10 6 6]
[2 10 6 6]
[1 2 10 6 6]
[2 10 6 6 6]
[1 2 10 6 6]
[2 10 6 6 6 6]
[Finished in 0.7s]
slice[1]=10的修改导致数值全都改变,可以看出来新建的切片是基于原来的切片数组的和他一起共同享有数组。同时我们可以给切片增加元素,切片长度和容量也会随之改变
在函数间传递切片
我们知道切片是3个字段构成的结构类型,所以在函数间以值的方式传递的时候,占用的内存非常小,成本很低。在传递复制切片的时候,其底层数组不会被复制,也不会受影响,复制只是复制的切片本身,不涉及底层数组。
func main() {
slice := []int{1, 2, 3, 4, 5}
fmt.Printf("%p\n", &slice)
modify(slice)
fmt.Println(slice)
}
func modify(slice []int) {
fmt.Printf("%p\n", &slice)
slice[1] = 10
}
输出结果
0xc420082060
0xc420082080
[1 10 3 4 5]
这两个切片的地址不一样,所以可以确认切片在函数间传递是复制的。而我们修改一个索引的值后,发现原切片的值也被修改了,说明它们共用一个底层数组。