以下代码正常工作 - 输出: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/

10-11 10:54