Golang中切片var a []int在首次使用前是否分配内存?
Golang中切片var a []int在首次使用前是否分配内存? 它不会分配相当于两个整型的内存吗:一个用于存储长度0,另一个用于存储指向底层数组的nil指针?
它会在首次使用时分配这两个整型吗?
另外,你更倾向于哪一种: var a []int VS a := []int{}
这个问题是倒数第二个,在底部,来自这里 https://www.toptal.com/go/interview-questions
[]Type 的零值是 nil,因此在实际创建非零值之前无需进行分配。
此外,var a []int 并不等同于 a := []int{},因为后者应该已经用非零值进行了初始化。
更多关于Golang中切片var a []int在首次使用前是否分配内存?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
嗨 @petrus
说得对,总结一下:
所以在运行时分配的是:
对于 var a []int:
type slice struct { <- 3个字段,每个字段一个int
array nil <- nil指针
len 0
cap 0
}
对于 t := []string{}:
type slice struct { <- 3个字段,每个字段一个int
array 0x-... <- 一个实际的指针
len 0
cap 0
}
从内存角度看,它们占用的空间相同。一个具有 nil 内部指针,另一个具有非 nil 内部指针。
JOhn_Stuart: 这是区别吗?
不。这才是区别。
package main
import (
"fmt"
"unsafe"
)
type slice struct {
array unsafe.Pointer
len int
cap int
}
func main() {
var a []int
printSlice(&a)
fmt.Println()
b := []int{}
printSlice(&b)
fmt.Println()
}
func printSlice(p *[]int) {
s := *p
fmt.Printf("%[1]v %[2]p %[1]T %[3]t\n", s, p, s == nil)
ss := (*slice)(unsafe.Pointer(p))
fmt.Println(ss.array, ss.len, ss.cap)
}
[] 0xc00000c0a0 []int true
<nil> 0 0
[] 0xc00000c0c0 []int false
0x586a00 0 0
a 和 b 的声明在地址 0xc00000c0a0 和 0xc00000c0c0 处分配了零值切片结构体。将复合字面量 []int{} 赋值给 b 则在地址 0x586a00 处分配了一个底层数组。
在Go语言中,var a []int 声明一个切片,但不会分配底层数组的内存。它确实会分配一个切片头(slice header),其中包含三个字段:指向底层数组的指针(nil)、长度(0)和容量(0)。切片头本身会分配内存,通常占用24字节(64位系统上,每个字段8字节)。
切片头的内存分配发生在声明时,而不是首次使用时。例如:
var a []int // 切片头已分配,指针为nil,长度和容量为0
fmt.Println(a == nil) // 输出:true
对于 a := []int{},这会创建一个非nil的空切片。它同样会分配切片头,并且可能分配一个底层数组(具体取决于编译器优化)。但即使底层数组可能被优化掉,切片头仍然是非nil的。例如:
a := []int{} // 切片头已分配,指针可能指向一个零大小的数组或为nil(取决于编译器)
fmt.Println(a == nil) // 输出:false
性能上,var a []int 通常更优,因为它避免了可能的底层数组分配。使用 []int{} 时,编译器可能分配一个零大小的数组,这可能导致额外的内存分配。
实际选择取决于需求:
- 如果需要表示“未初始化”的切片,使用
var a []int(nil切片)。 - 如果需要空但已初始化的切片,使用
a := []int{}(空切片)。
示例代码:
package main
import "fmt"
func main() {
var nilSlice []int
emptySlice := []int{}
fmt.Printf("nilSlice: %v, len=%d, cap=%d, is nil? %t\n",
nilSlice, len(nilSlice), cap(nilSlice), nilSlice == nil)
fmt.Printf("emptySlice: %v, len=%d, cap=%d, is nil? %t\n",
emptySlice, len(emptySlice), cap(emptySlice), emptySlice == nil)
}
输出:
nilSlice: [], len=0, cap=0, is nil? true
emptySlice: [], len=0, cap=0, is nil? false
在大多数情况下,var a []int 是更安全且性能更好的选择,除非明确需要一个非nil的空切片。

