版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zzuchengming/article/details/88617493
slice 数据结构
type slice struct {
array unsafe.Pointer //指向底层数组的指针
len int //切片中元素个数
cap int //切片总容量
}
-
基于数组或者slice生成一个slice的时候,新的slice和原来数组/slice 的底层数组是同一个
-
基于数组或者slice生成slice的cap=原来对应的数组长度-现在slice的第一个元素对应的索引
-
slice 作为参数传递的是 副本,但是对应的数组的指针不变
package main
import "fmt"
var arr = []int{1,2,3,4,5}
func testSliceAsParam1(s1 []int) {
s1[0] = 5 //扩容前修改,影响传入slice,因为s1指向底层数组没变,但是底层数组元素值变了
return
}
func testSliceAsParam2(s1 []int) {
s1 = append(s1, 6) //扩容后修改,不影响传入slice,因为扩容后产生了新的底层数组,函数体内的
//副本s1,其指向底层数组的指针已经改变,指向新生成的底层数组,此时修改只
//是修改新的底层数组,原s1指向的底层数组元素值没变
s1[0] = 9
return
}
func main() {
s1 := arr[:5]
fmt.Println("before1: ")
fmt.Println(s1)// [1 2 3 4 5]
testSliceAsParam1(s1)
fmt.Println("after1: ")
fmt.Println(s1)// [5 2 3 4 5]
testSliceAsParam2(s1)
fmt.Println("after2: ")
fmt.Println(s1) //[5 2 3 4 5]
}
- 扩容规则:
在一般的情况下,你可以简单地认为新切片的容量(以下简称新容量)将会是原切片容量(以下简称原容量)的 2 倍。
但是,当原切片的长度(以下简称原长度)大于或等于1024时,Go 语言将会以原容量的1.25倍作为新容量的基准(以下新容量基准)
slice 数组指针什么情况下会发生变化?
确切地说,一个切片的底层数组永远不会被替换。为什么?虽然在扩容的时候 Go 语言一定会生成新的底层数组,但是它也同时生成了新的切片。它是把新的切片作为了新底层数组的窗口,而没有对原切片及其底层数组做任何改动。
测试:
append扩容后,确实产生了新的底层数组,也生成了新的切片;但当你用原切片作为append的接收者,因为‘=’是值传递,你看到切片的地址是没有改变的。
package main
import "fmt"
var arr = []int{1,2,3,4,5}
func main() {
s1 := arr[:5]
fmt.Printf("%p", &s1) //0xc0420023e0
fmt.Println()
s2 := append(s1, 6) //确实产生了新的底层数组和新的切片
fmt.Printf("%p", &s2) //0xc042002420
fmt.Println()
s1 = s2 //值传递,这里等价于s1 = append(s1,6)
fmt.Printf("%p", &s1) //0xc0420023e0
}