相关问题在这里https://stackoverflow.com/a/12965872/6421681 .
在 go 中,您可以:
func numsInFactorial(n int) (nums []int) {
// `nums := make([]int)` is not needed
for i := 1; i <= n; i++ {
nums = append(nums, i)
}
return
}
但是,以下内容不起作用:
func mapWithOneKeyAndValue(k int, v int) (m map[int]int) {
m[k] = v
return
}
抛出一个错误:
panic :分配给 nil 映射中的条目
相反,您必须:
func mapWithOneKeyAndValue(k int, v int) map[int]int {
m := make(map[int]int)
m[k] = v
return
}
我找不到此行为的文档。
我已经通读了 effective go 的所有内容,那里也没有提到它。
我知道命名的返回值已定义(即内存已分配;接近于 new
所做的)但未初始化(因此 make
行为未被复制)。
经过一些实验,我相信这种行为可以简化为理解以下代码的行为:
func main() {
var s []int // len and cap are both 0
var m map[int]int
fmt.Println(s) // works... prints an empty slice
fmt.Println(m) // works... prints an empty map
s = append(s, 10) // returns a new slice, so underlying array gets allocated
fmt.Println(s) // works... prints [10]
m[10] = 10 // program crashes, with "assignment to entry in nil map"
fmt.Println(m)
}
问题似乎是 append
可能会调用 make
并分配一个新的 slice ,检测到 s
的容量为 0
。但是,map
永远不会进行显式初始化。
这个 SO 问题的原因有两个。首先,我想记录下 SO 上的行为。其次,为什么该语言允许 slice
和 map
的非初始化定义?根据我到目前为止的经验,它似乎是一种实用的语言(即未使用的变量会导致编译失败,gofmt 强制正确格式化),因此阻止代码编译是有意义的。
最佳答案
尝试按索引分配 nil slice - 你会得到“ panic :运行时错误:索引超出范围”(例如:https://play.golang.org/p/-XHh1jNyn5g)
append 函数与 nil 一起工作的唯一原因是 append 函数可以对给定的 slice 进行重新分配。 例如,如果您尝试将第 6 个元素附加到当前容量为 5 的 5 个元素的 slice ,它将创建具有新容量的新数组,从旧数组复制所有信息,并交换给定 slice 中的数据数组指针。在我的理解中,它只是动态数组的golang实现。
因此,nil slice 只是容量不足的 slice 的特例,因此它会在任何追加操作时重新分配。
有关 https://blog.golang.org/go-slices-usage-and-internals 的更多详细信息
关于go - slice 和映射之间的行为差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52681793/