为啥 Go 输入 nil?
Posted
技术标签:
【中文标题】为啥 Go 输入 nil?【英文标题】:Why does Go have typed nil?为什么 Go 输入 nil? 【发布时间】:2013-11-14 16:45:12 【问题描述】:为什么 Go 有 typed nil
?为方便起见,它会引发显式接口构造检查。无类型的nil
有什么问题,设计师想用有类型的nil
解决什么问题?
【问题讨论】:
如果 Go 使用像 SwiftOptional<T>
这样的显式类型 nil 可能会更好。
相关,在这里找一些推理和解释:Hiding nil values, understanding why golang fails here
【参考方案1】:
听起来你在问这个错误信息:
http://play.golang.org/p/h80rmDYCTI
package main
import "fmt"
type A struct
type B struct
func (a *A) Foo()
fmt.Println("A")
func (b *B) Foo()
fmt.Println("B")
func main()
n := nil
n.Foo()
打印出来:
prog.go:17: use of untyped nil
[process exited with non-zero status]
在那个例子中,程序应该打印“A”还是“B”?
您必须帮助编译器做出决定。这样做的方法是指定n
的类型。
例如:
http://play.golang.org/p/zMxUFYgxpy
func main()
var n *A
n.Foo()
打印“A”。
在其他语言中,如果n
是nil
或其等效项,n.Foo()
可能会立即崩溃。 Go 的语言设计者决定让你决定应该发生什么。如果您在不检查 nil
的情况下访问指针,您将获得与其他语言相同的行为。
【讨论】:
除非您所指的错误消息是“与远程服务器通信时出错”。 (这就是我得到的),您可能希望直接在答案中包含更多信息,而不是通过链接。 在这里我要强调一点,在nil
上调用类型化方法既有意义又有用。
@KeithThompson 好点。我也合并了代码。达斯汀,好点。这与问题无关,但值得简要提及。谢谢你们!【参考方案2】:
这是因为类型安全。 nil
实际上是 Go 中 未初始化 变量的值。切片、映射、函数、通道、指针和接口的nil
值不属于同一类型,也不具有可比性。详情请见The language spec。
编辑:正如@newacct 所指出的,正确的技术术语是"zero value" 类型:
当通过声明或调用 make 或 new 分配内存来存储值时,并且未提供显式初始化,则为内存提供默认初始化。这样一个值的每个元素的类型都设置为零值:布尔值为 false,整数为 0,浮点数为 0.0,字符串为 "",指针、函数、接口、切片、通道和映射为 nil。
Playground example
Why is my nil error value not equal to nil? 在Go FAQ 中还有一些关于 nil 接口和错误的信息。
【讨论】:
“实际上是未初始化变量的值” 从技术上讲,它被称为类型的“零值”。所有类型的值都为零。变量未初始化。 @newacct 我使用的是语言规范 (golang.org/ref/spec) 中的术语,他们声明“未初始化切片的值是nil
”,“未初始化指针的值是nil
" 等。从同一个文档中,我可以看到我在回答中提到的所有类型的“零值”都是 nil
是正确的。我认为“零值”的松散、不精确的定义是“未初始化的”,因为 Go 的作者似乎很乐意在实际规范中使用这两者。我已经更新了我的答案,感谢您提供正确的术语。【参考方案3】:
Go 中的所有变量都需要有一个类型。使用:=
运算符从右侧表达式的类型推断类型。
x := [0]int // var x [0]int
y := make(chan int) // var y chan int
z := map[int]int // var z map[int]int
a := func(int) // var a func(int)
b := 42 // var b int
c := 42.0 // var c float64
对于几乎任何表达式,它的类型都是明确的,因为需要在某处显式指定类型 - 或者在数字文字的情况下,在未指定时具有默认值。此规则的唯一例外是nil
。
n := nil // var n ???
nil
是以下的有效值。
当用户键入 nil
时,类型没有很好的默认值,因此 Golang 拒绝了这种需要显式类型规范的要求。
【讨论】:
这个答案对我来说是正确的。不知道为什么它被否决了。【参考方案4】:如果没有 typed-nil,您将无法使用带有 nil
值的短赋值语句 :=
。
a := nil // Error: use of untyped nil
b := error(nil) // OK
同样,它启用了以下单行:
result, err := "A good result", error(nil)
写上类似的东西有时可能会提供一些便利。
但是请注意,nil
不是关键字或文字——Go 确实 not 具有内置或标准的 typed-nil 值。 Typed-nil 仅作为以下之一的结果存在:
nil
(直接或间接)分配给类型化值
将nil
标识符转换为类型(如上面的示例所示)。
这是一个关于类型化 nil 和接口的微妙之处的剪辑:GopherCon 2015: Kevin Cantwell - What Could Go Wrong?
【讨论】:
以上是关于为啥 Go 输入 nil?的主要内容,如果未能解决你的问题,请参考以下文章
当非默认是输入通道时,为啥 go 中的选择总是进入默认情况?