slice原理我们之前看过一篇文章:
https://www.jianshu.com/p/843aa553b461
问题代码,求a与b的值
package main
import (
"fmt"
)
func main() {
var a = make([]int, 0, 10)
a=append(a,1,2)
b:=append(a,3)
b[0] = 99
fmt.Println(a)
fmt.Println(b)
}
答案:
[99 2]
[99 2 3]
问题来了:通过append之后得到的切片更改元素值到底对原切片有没有影响?为什么?
为了搞懂它我们测试了一下,并且加了注释方便大家深入理解。
package main
import (
"fmt"
"reflect"
"unsafe"
)
func deferFunc(dsl []int) {
//1、sl通过方法名传递,所以 sl是结构体值拷贝,所以会是一个新对象,参见pointer和append原理
//2、新对象因为拷贝了ptr指针, 所以ptr对象不会变化, 参见:reflect.SliceHeader{Data:}
//3、dsl与sl的ptr虽然相同,但是len不同,所以sl新增的元素对dsl无影响
fmt.Printf("%s\t pointer:%p, struct: %#v, values:%v\n", "defer_before_append", &dsl, *((*reflect.SliceHeader)(unsafe.Pointer(&dsl))), dsl)
dsl = append(dsl, 99)
fmt.Printf("%s\t pointer:%p, struct: %#v, values:%v\n", "defer_after_append", &dsl, *((*reflect.SliceHeader)(unsafe.Pointer(&dsl))), dsl)
}
func main() {
//拓展一下对象go的对象打印
//slice是一个结构体
fmt.Println("==========slice print=============")
s:=[]int{1}
//打印结构体指针地址
fmt.Printf("%p\n",&s)
//打印结构体首元素指针方法1
fmt.Printf("%p\n",s)
//打印结构体首元素指针方法2
fmt.Printf("%p\n",&s[0])
//打印结构体值:可以印证:打印结构体首元素指针方法1
fmt.Printf("%#v\n",*((*reflect.SliceHeader)(unsafe.Pointer(&s))))
fmt.Println("==========================")
var sl = make([]int, 0, 10)
for i := 0; i < 15; i++ {
//0、append会发生值拷贝,如果是自身对象会复用,所以地址不会变化,参见pointer
//1、不需要扩容时 ptr对象不会变化, 参见:reflect.SliceHeader{Data:}
//2、扩容成功时,数据会发生拷贝所以 ptr对象会变化, 参见:reflect.SliceHeader{Data:}
sl = append(sl, i)
fmt.Printf("%s\t pointer:%p, struct: %#v, values:%v\n", "before_defer", &sl, *((*reflect.SliceHeader)(unsafe.Pointer(&sl))), sl)
}
defer deferFunc(sl)
//1、append赋值给一个新对象时,因为是值拷贝,所以会是一个新对象,参见pointer和append原理 https://blog.golang.org/go-slices-usage-and-internals
//2、新对象因为拷贝了ptr指针, 所以ptr对象不会变化, 参见:reflect.SliceHeader{Data:}
sl2 := append(sl, 5)
fmt.Printf("%s\t pointer:%p, struct: %#v, values:%v\n", "new_struct", &sl2, *((*reflect.SliceHeader)(unsafe.Pointer(&sl2))), sl2)
sl2[0] = 100
//1、sl与sl2的ptr相同,所以sl2对ptr的操作会对sl数据产生影响,所以sl[0]=100
//2、sl与sl2的ptr虽然相同,但是len不同,所以sl2新增的元素对sl无影响
sl = append(sl, 4)
fmt.Printf("%s\t pointer:%p, struct: %#v, values:%v\n", "after_defer", &sl, *((*reflect.SliceHeader)(unsafe.Pointer(&sl))), sl)
}
==========slice print=============
0xc000088020
0xc000090000
0xc000090000
reflect.SliceHeader{Data:0xc000090000, Len:1, Cap:1}
==========================
before_defer pointer:0xc000088060, struct: reflect.SliceHeader{Data:0xc000094000, Len:1, Cap:10}, values:[0]
before_defer pointer:0xc000088060, struct: reflect.SliceHeader{Data:0xc000094000, Len:2, Cap:10}, values:[0 1]
before_defer pointer:0xc000088060, struct: reflect.SliceHeader{Data:0xc000094000, Len:3, Cap:10}, values:[0 1 2]
before_defer pointer:0xc000088060, struct: reflect.SliceHeader{Data:0xc000094000, Len:4, Cap:10}, values:[0 1 2 3]
before_defer pointer:0xc000088060, struct: reflect.SliceHeader{Data:0xc000094000, Len:5, Cap:10}, values:[0 1 2 3 4]
before_defer pointer:0xc000088060, struct: reflect.SliceHeader{Data:0xc000094000, Len:6, Cap:10}, values:[0 1 2 3 4 5]
before_defer pointer:0xc000088060, struct: reflect.SliceHeader{Data:0xc000094000, Len:7, Cap:10}, values:[0 1 2 3 4 5 6]
before_defer pointer:0xc000088060, struct: reflect.SliceHeader{Data:0xc000094000, Len:8, Cap:10}, values:[0 1 2 3 4 5 6 7]
before_defer pointer:0xc000088060, struct: reflect.SliceHeader{Data:0xc000094000, Len:9, Cap:10}, values:[0 1 2 3 4 5 6 7 8]
before_defer pointer:0xc000088060, struct: reflect.SliceHeader{Data:0xc000094000, Len:10, Cap:10}, values:[0 1 2 3 4 5 6 7 8 9]
before_defer pointer:0xc000088060, struct: reflect.SliceHeader{Data:0xc000098000, Len:11, Cap:20}, values:[0 1 2 3 4 5 6 7 8 9 10]
before_defer pointer:0xc000088060, struct: reflect.SliceHeader{Data:0xc000098000, Len:12, Cap:20}, values:[0 1 2 3 4 5 6 7 8 9 10 11]
before_defer pointer:0xc000088060, struct: reflect.SliceHeader{Data:0xc000098000, Len:13, Cap:20}, values:[0 1 2 3 4 5 6 7 8 9 10 11 12]
before_defer pointer:0xc000088060, struct: reflect.SliceHeader{Data:0xc000098000, Len:14, Cap:20}, values:[0 1 2 3 4 5 6 7 8 9 10 11 12 13]
before_defer pointer:0xc000088060, struct: reflect.SliceHeader{Data:0xc000098000, Len:15, Cap:20}, values:[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
new_struct pointer:0xc000088260, struct: reflect.SliceHeader{Data:0xc000098000, Len:16, Cap:20}, values:[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 5]
after_defer pointer:0xc000088060, struct: reflect.SliceHeader{Data:0xc000098000, Len:16, Cap:20}, values:[100 1 2 3 4 5 6 7 8 9 10 11 12 13 14 4]
defer_before_append pointer:0xc0000882c0, struct: reflect.SliceHeader{Data:0xc000098000, Len:15, Cap:20}, values:[100 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
defer_after_append pointer:0xc0000882c0, struct: reflect.SliceHeader{Data:0xc000098000, Len:16, Cap:20}, values:[100 1 2 3 4 5 6 7 8 9 10 11 12 13 14 99]