这在规格:切片表达式 https://golang.org/ref/spec#Slice_expressions.
该数组不会被复制,但切片表达式的结果将是引用该数组的切片。在 Go 中,从函数或方法返回局部变量或其地址是完全安全的,Go 编译器执行逃逸分析 https://en.wikipedia.org/wiki/Escape_analysis确定一个值是否可以逃逸该函数,如果可以(或者更确切地说,如果它不能证明一个值不能逃逸),它将在堆上分配它,以便在函数返回后可用。
切片表达式:tmp[:end]
means tmp[0:end]
(因为缺少一个low
索引默认为零)。由于您没有指定容量,因此默认为len(tmp) - 0
这是len(tmp)
这是100
.
您还可以通过使用控制结果切片的容量全切片表达式,其形式为:
a[low : high : max]
这将结果切片的容量设置为max - low
.
更多示例来阐明生成的切片的长度和容量:
var a [100]int
s := a[:]
fmt.Println(len(s), cap(s)) // 100 100
s = a[:50]
fmt.Println(len(s), cap(s)) // 50 100
s = a[10:50]
fmt.Println(len(s), cap(s)) // 40 90
s = a[10:]
fmt.Println(len(s), cap(s)) // 90 90
s = a[0:50:70]
fmt.Println(len(s), cap(s)) // 50 70
s = a[10:50:70]
fmt.Println(len(s), cap(s)) // 40 60
s = a[:50:70]
fmt.Println(len(s), cap(s)) // 50 70
尝试一下去游乐场 https://play.golang.org/p/ECJck-Px0p.
避免堆分配
如果您想在堆栈上分配它,则不能返回任何指向它(或其部分)的值。如果将其分配在堆栈上,则无法保证返回后它仍然可用。
一个可能的解决方案是将一个指向数组的指针作为函数的参数传递(并且您可以返回一个指定useful函数填充的部分),例如:
func foo(tmp *[100]uint64) []uint64 {
// ...
return tmp[:end]
}
如果调用者函数创建数组(在堆栈上),这不会导致“重新分配”或“移动”到堆:
func main() {
var tmp [100]uint64
foo(&tmp)
}
Running go run -gcflags '-m -l' play.go
,结果是:
./play.go:8: leaking param: tmp to result ~r1 level=0
./play.go:5: main &tmp does not escape
变量tmp
没有移动到堆。
注意[100]uint64
被认为是要在堆栈上分配的小数组。详情请参阅关于堆栈分配,Go 中什么被视为“小”对象? https://stackoverflow.com/questions/42243197/what-is-considered-small-object-in-go-regarding-stack-allocation/42244087#42244087