SliceHeader--slice的本质
问题:
slice空间容量足够,调用方法前后其地址并不会改变,那么为何append后的切片内部成员不会改变? 默认拷贝的副本是slice引用,应该要能修改或者添加成员才符合预期的
type Slice []int
func (A Slice)Append(value int) {
A = append(A, value)
}
func main() {
mSlice := make(Slice, 10, 20)
mSlice.Append(5)
fmt.Println(mSlice)
}
问题分析
以上的输出打印中,可以看到mSlice并没有任何变化,就是方法Append没有起任何作用。
append后的Slice已经不是原来的Slice了。append返回的Slice的指针和原Slice的指针一样的,怎么会不是一个呢?我们来测试一次,修改代码如下:
func (A Slice)Append(value int) {
A1 := append(A, value)
fmt.Printf("%p\n%p\n",A,A1)
}
>>>
0xc00009e000
0xc00009e000
A1存储append方法返回的Slice,然后打印返回A1和原A的指针地址,发现的确一样。在make一个Slice的时候会发现,是可以有三个参数的,一个是数据、一个是长度、一个是容量,也就是说,Slice是这样的一个结构。
SliceHeader
SliceHeader是Slice运行时的具体表现,它的结构定义如下:
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
对应Slice的三要素,Data指向具体的底层数据源数组,Len代表长度,Cap代表容量。
Slice就是SliceHeader,把Slice转化为SliceHeader,来看看A和A1内部具体的字段值,判断是否一致,修改Append方法如下:
func (A Slice)Append(value int) {
A1 := append(A, value)
sh:=(*reflect.SliceHeader)(unsafe.Pointer(&A))
fmt.Printf("A Data:%d,Len:%d,Cap:%d\n",sh.Data,sh.Len,sh.Cap)
sh1:=(*reflect.SliceHeader)(unsafe.Pointer(&A1))
fmt.Printf("A1 Data:%d,Len:%d,Cap:%d\n",sh1.Data,sh1.Len,sh1.Cap)
}
通过unsafe.Pointer指针进行强制类型转换,都转换为*reflect.SliceHeader类型后,分别输出他们的Data、Len、Cap字段,输出的结果:
A Data:824634368000,Len:10,Cap:20
A1 Data:824634368000,Len:11,Cap:20
Len不一样,并不是一个Slice,所以使用append方法并没有改变原来的A,而是新生成了一个A1,即使通过代码 A = append(A, value) 进行复制,也只是一个mSlice的拷贝A的指向被改变了,而且这个A只在Append方法内有效,mSlice本身并没有改变,所以输出的mSlice不会有任何变化。
解疑
如果设置的Len是10,Cap是20,因为Cap足够大,所以内置函数append并没有生成新的底层数组,把Cap改为10。
type Slice []int
func (A Slice)Append(value int) {
A1 := append(A, value)
sh:=(*reflect.SliceHeader)(unsafe.Pointer(&A))
fmt.Printf("A Data:%d,Len:%d,Cap:%d\n",sh.Data,sh.Len,sh.Cap)
sh1:=(*reflect.SliceHeader)(unsafe.Pointer(&A1))
fmt.Printf("A1 Data:%d,Len:%d,Cap:%d\n",sh1.Data,sh1.Len,sh1.Cap)
}
func main() {
mSlice := make(Slice, 10, 10)
mSlice.Append(5)
fmt.Println(mSlice)
}
发现两个Slice的Data不再一样
A Data:824633794880,Len:10,Cap:10
A1 Data:824634302464,Len:11,Cap:20
在append的时候,发现Cap不够,生成了一个新的Data数组,用于存储新的数据,并且同时扩充了Cap容量。

浙公网安备 33010602011771号