一个相关的问题在这里https://stackoverflow.com/a/12965872/6421681。
在旅途中,您可以执行以下操作:
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: assignment to entry in nil map
相反,您必须:
func mapWithOneKeyAndValue(k int, v int) map[int]int {
m := make(map[int]int)
m[k] = v
return
}
我找不到有关此行为的文档。
我已经阅读了所有有效的建议,也没有提及。
我知道已定义了命名的返回值(即,已分配内存;接近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
并分配了一个新的切片,以检测s
的容量为0
。但是,map
从未得到显式初始化。
这样的SO问题的原因有两个方面。首先,我想记录一下SO上的行为。其次,为什么该语言允许slice
和map
的非初始化定义?根据我到目前为止的经验,这似乎是一种实用的语言(即,未使用的变量会导致编译失败,gofmt会强制正确格式化),因此防止代码编译是有意义的。
答案 0 :(得分:4)
尝试按索引在nil slice中分配-您将收到“紧急情况:运行时错误:索引超出范围”(例如:https://play.golang.org/p/-XHh1jNyn5g)
append函数与nil一起使用的唯一原因是,append函数可以对给定的切片进行重新分配。 例如,如果您尝试将第6个元素追加到当前容量为5的5个元素的切片中,它将创建具有新容量的新数组,复制旧数组中的所有信息,并交换给定切片中的数据数组指针。以我的理解,这只是动态数组的golang实现。
因此,nil slice只是slice的一种特殊情况,它的容量不足,因此可以在任何追加操作中重新分配它。
有关https://blog.golang.org/go-slices-usage-and-internals的更多详细信息
答案 1 :(得分:3)
来自https://blog.golang.org/go-maps-in-action
读取时,nil映射的行为类似于空映射,但是尝试写入nil映射会导致运行时出现紧急情况;不要那样做要初始化地图,请使用内置的make函数
似乎nil映射被认为是有效的空映射,这就是他们不自动为其分配内存的原因。