问题描述
注意: Declare slice or make slice?不能回答我的问题,因为那是将slice声明与make slice进行比较,而我的问题是将slice文字与make slice进行比较。该问题的答案很简单,因为裸切片声明会创建一个nil切片,但是,如果您仔细阅读下面的问题,我根本不会创建nil切片。
有两种方法可以创建切片并将其附加到切片。下面的代码将两种方式分别显示为Example 1
和Example 2
。
package main
import (
"fmt"
)
func main() {
// Example 1
a := []int{}
fmt.Printf("len(a): %d; cap(a): %d; a: %v\n",len(a),cap(a),a)
a = append(a,10,20,30,40,50)
fmt.Printf("len(a): %d; cap(a): %d; a: %v\n",a)
// Example 2
b := make([]int,0)
fmt.Printf("len(b): %d; cap(b): %d; b: %v\n",len(b),cap(b),b)
b = append(b,50)
fmt.Printf("len(b): %d; cap(b): %d; b: %v\n",b)
}
输出:
len(a): 0; cap(a): 0; a: []
len(a): 5; cap(a): 6; a: [10 20 30 40 50]
len(b): 0; cap(b): 0; b: []
len(b): 5; cap(b): 6; b: [10 20 30 40 50]
是否有两种方法创建等效的[]int{}
和make([]int,0)
空切片?他们在行为上有什么改变吗?
解决方法
我稍微修改了您的示例
// Example 1
a := []int{}
pa := &a
// Example 2
b := make([]int,0)
pb := &b
runtime.KeepAlive(pa)
runtime.KeepAlive(pb)
它编译为:
*** main.go#12 > a := []int{}
0x4e56a9 488d0538bb1100 lea rax,ptr [runtime.zerobase]
0x4e56b0 4889442470 mov qword ptr [rsp+0x70],rax
0x4e56b5 8400 test byte ptr [rax],al
0x4e56b7 eb00 jmp 0x4e56b9
0x4e56b9 4889842418010000 mov qword ptr [rsp+0x118],rax
0x4e56c1 0f57c0 xorps xmm0,xmm0
0x4e56c4 0f11842420010000 movups xmmword ptr [rsp+0x120],xmm0
*** main.go#13 > pa := &a
0x4e56cc 488d842418010000 lea rax,ptr [rsp+0x118]
0x4e56d4 4889442460 mov qword ptr [rsp+0x60],rax
*** main.go#16 > b := make([]int,0)
0x4e56d9 488d0520020100 lea rax,ptr [__image_base__+1005824]
0x4e56e0 48890424 mov qword ptr [rsp],rax
0x4e56e4 0f57c0 xorps xmm0,xmm0
0x4e56e7 0f11442408 movups xmmword ptr [rsp+0x8],xmm0
0x4e56ec e8bf49f6ff call $runtime.makeslice
0x4e56f1 488b442418 mov rax,qword ptr [rsp+0x18]
0x4e56f6 4889842400010000 mov qword ptr [rsp+0x100],rax
0x4e56fe 0f57c0 xorps xmm0,xmm0
0x4e5701 0f11842408010000 movups xmmword ptr [rsp+0x108],xmm0
*** main.go#17 > pb := &b
0x4e5709 488d842400010000 lea rax,ptr [rsp+0x100]
0x4e5711 4889442458 mov qword ptr [rsp+0x58],rax
似乎make([]int,0)
会导致堆分配(通过$runtime.makeslice()
),但不会-深入sources表示makeslice()
还返回了基于&zerobase
的切片:
if size == 0 {
return unsafe.Pointer(&zerobase)
}
因此,这两个代码段都具有相同的切片结构,其中数据指针设置为zerobase
。