说在前面
- go版本:go1.18.4 windows/amd64
问题提出
-
对于下述代码段,输出是什么呢?
type SliceStrcut struct { List []uint32 } func (this *SliceStrcut) Get() []uint32 { return this.List } func main() { s := &SliceStrcut{ List: []uint32{ 1, 2, 3}, } tmp := s.Get() tmp = append(tmp[:1], tmp[2:]...) fmt.Println(s.List) }
答案是:
[1 3 3]
-
其实上述代码具有一定的迷惑性,换成下述代码结果也是一样的
func main() { s := []uint32{ 1, 2, 3} tmp := s tmp = append(tmp[:1], tmp[2:]...) fmt.Println(s) }
-
所以重点是搞清楚在slice赋值的时候发生了什么
心路历程
- 大部分人都知道slice并不是一个正真的数组,只是描述了一个数组。所以我自然而然的想到,slice应该是个指针,有意思的是,当使用
%p
打印slice的时候,两者的地址是一样的,如下:func main() { s := []uint32{ 1, 2, 3} tmp := s tmp = append(tmp[:1], tmp[2:]...) fmt.Printf("%p, %p", s, tmp) } // 输出 // 0xc00000a9c0, 0xc00000a9c0
- 那我对
slice是指针
就更加深信不疑了。那么,问题来了,既然是指针,为什么s
和tmp
不一样呢?func main() { s := []uint32{ 1, 2, 3} tmp := s tmp = append(tmp[:1], tmp[2:]...) fmt.Println(s, cap(s), len(s)) fmt.Println(tmp, cap(tmp), len(tmp)) } // 输出 // [1 3 3] 3 3 // [1 3] 3 2
- 然后开始找资料,发现slice应该是个结构体,这就很好的解释了为啥
s
和tmp
不一样,因为本身就是两个不同的变量嘛,所以在使用append进行删除的时候只改了tmp
,而没有动到s
; - 不过,如果slice是结构体,为什么
%p
打印的地址一样?虽然说使用取指符打印的地址值确实不一样func main() { s := []uint32{ 1, 2, 3} tmp := s tmp = append(tmp[:1], tmp[2:]...) fmt.Printf("%p %p\n", s, tmp) fmt.Printf("%p %p\n", &s, &tmp) } // 输出 // 0xc00000a9c0 0xc00000a9c0 // 0xc000004150 0xc000004168
- 继续找资料,原来
%p
打印slice时,会输出第一个元素的地址,原来如此!