slice 基本实现
Golang中的slice,是一个看似array却不是array的复合结构。切片顾名思义,就是数组切下来的一个片段。slice结构大致存储了三个部分,第一部分为指向底层数组的指针ptr,其次就是切片的大小len和切片的容量cap:
有一个数组arr是一个包含五个int类型的结构,它的切片slice只是从其中取了1到3这几个数字。我们同样可以在生成一个切片 slice2 := arr[2:5], 所取的就是数组后面的连续块。它们共同使用arr作为底层的结构,可以看见公用了数字的第3,4个元素。修改其中任何一个,都能改变两个切片的值。
func main() {
arr := [5]int{0, 1, 2, 3, 4}
fmt.Println(arr)
slice := arr[1:4]
slice2 := arr[2:5]
fmt.Printf("arr %v, slice1 %v, slice2 %v, %p %p %p\n", arr, slice, slice2, &arr, &slice, &slice2)
fmt.Printf("arr[2]%p slice[1] %p slice2[0]%p\n", &arr[2], &slice[1], &slice2[0])
arr[2] = 2222
fmt.Printf("arr %v, slice1 %v, slice2 %v\n", arr, slice, slice2)
slice[1] = 1111
fmt.Printf("arr %v, slice1 %v, slice2 %v\n", arr, slice, slice2)
}
输出的值为:
[0 1 2 3 4]
arr [0 1 2 3 4], slice1 [1 2 3], slice2 [2 3 4], 0xc42006e0c0 0xc4200660c0 0xc4200660e0
arr[2]0xc42006e0d0 slice[1] 0xc42006e0d0 slice2[0]0xc42006e0d0
arr [0 1 2222 3 4], slice1 [1 2222 3], slice2 [2222 3 4]
arr [0 1 1111 3 4], slice1 [1 1111 3], slice2 [1111 3 4]
由此可见,数组的切片,只是从数组上切一段数据下来,不同的切片,其实是共享这些底层的数据。不过这些本身是不一样的对象,其内存地址都不一样。
从数组中切下来形成切片很好理解,有时候我们用make函数创建切片,实际上golang会在底层创建一个匿名的数组。如果从新的slice再切,那么新创建的两个切片都共享这个底层的匿名数组。
func main() {
slice := make([]int, 5)
for i:=0; i<len(slice);i++{
slice[i] = i
}
fmt.Printf("slice %v \n", slice)
slice2 := slice[1:4]
fmt.Printf("slice %v, slice2 %v \n", slice, slice2)
slice[1] = 1111
fmt.Printf("slice %v, slice2 %v \n", slice, slice2)
}
输出如下:
slice [0 1 2 3 4]
slice [0 1 2 3 4], slice2 [1 2 3]
slice [0 1111 2 3 4], slice2 [1111 2 3]
slice的复制
既然slice的创建依赖于数组,有时候新生成的slice会修改,但又不想修改原来的切片或数组。此时就需要针对原来的切片进行复制了。
func main() {
slice := []int{0, 1, 2, 3, 4}
slice2 := slice[1:4]
slice3 :=