以下代码正常工作 - 输出:You chose Test 1
package main
import (
"fmt"
)
type TNameMap map[int]string
var nameMap TNameMap
func init() {
nameMap = make(TNameMap)
nameMap[1] = "You chose Test 1"
nameMap[2] = "You chose Test 2"
nameMap[3] = "You chose Test 3"
}
func main() {
fmt.Println(nameMap[1])
}
如果我注释掉
init()
中的第一行,即 //nameMap = make(TNameMap)
,当 main()
运行时我会感到 panic ,因为 nameMap
从未被初始化:panic: runtime error: assignment to entry in nil map
但是 - 如果在
init()
我写 nameMap := make(TNameMap)
而不是
nameMap = make(TNameMap)
,我没有 panic ,但也没有输出 - main()
只是运行并且进程终止。我明白,如果我使用初始化运算符 -
nameMap := make(TNameMap)
- 我已经声明了一个新变量 nameMap
,它的范围只限于 init()
函数,因此只有包级别变量 var nameMap TNameMap
位于 main()
的范围内,导致没有输出,因为包级别var
没有 map 数据。但是,我很困惑:为什么在这种情况下我没有得到
panic
?如果 main()
正在对包 var 进行调用,它从未被初始化 - 那么为什么没有 panic
呢? 最佳答案
根据 Go 规范:
这意味着您可以 从 nil 映射中读取 ,但不能 写入 。就像 panic 说“ 将 分配给 nil map 中的条目”一样。如果您只注释掉 nameMap = make(TNameMap)
行,它将崩溃,因为您尝试在 init
中写入它(发生 panic 的地方)。如果您注释掉整个 init
,则 Println 不会崩溃,因为您被允许访问(读取)一个 nil 映射。
将赋值更改为声明只是掩盖了这里的真正问题,正在发生的事情是使所有赋值有效,然后丢弃结果。只要您使赋值有效(通过删除它们或创建临时变量),那么您将在 Println 中观察到相同的行为。
nil 映射返回的值始终是映射值类型的零值。所以 map[T]string
返回 ""
, map[T]int
返回 0
,依此类推。 (当然,如果您使用 val,ok := nilMap[key]
进行检查,那么 ok
将为假)。
关于variables - Go 初始化运算符,包作用域变量 - 混淆 :,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22291888/