为什么Go语言有类型化的nil值?

huangapple go评论88阅读模式
英文:

Why does Go have typed nil?

问题

为什么Go语言有类型化nil?它为了方便起见,引入了显式接口一致性检查。无类型的nil有什么问题,设计者们希望通过类型化的nil解决什么问题?

英文:

Why does Go have typed nil? It throws an explicit interface conformation check for convenience. What's the problem of untyped nil and what did the designers want to solve with typed nil?

答案1

得分: 23

听起来你在询问这个错误信息:

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"。

在其他语言中,如果nnil或其等效值,n.Foo()可能会立即崩溃。Go语言的设计者决定让你决定应该发生什么。如果在不检查nil的情况下访问指针,你将得到与其他语言相同的行为。

英文:

It sounds like you're asking about this error message:

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()
}

This prints:

prog.go:17: use of untyped nil
 [process exited with non-zero status]

In that example, should the program print "A" or "B"?

You have to help the compiler decide. The way you do that is by specifying the type of n.

For example:

http://play.golang.org/p/zMxUFYgxpy

func main() {
    var n *A
    n.Foo()
}

prints "A".

In other languages, n.Foo() might crash immediately if n is nil or its equivalent. Go's language designers decided to let you determine what should happen instead. If you access the pointer without checking for nil, you get the same behavior as in other languages.

答案2

得分: 19

这是由于类型安全性。在Go语言中,nil实际上是未初始化变量的值。对于切片、映射、函数、通道、指针和接口来说,它们的nil值不是同一类型,也不能进行比较。详细信息请参阅语言规范

编辑:正如@newacct指出的,这个问题的正确技术术语是类型的“零值”("zero value")。

当为一个值分配内存时,无论是通过声明还是通过调用make或new,如果没有提供显式的初始化,该内存将被赋予默认初始化。这个值的每个元素都被设置为其类型的零值:布尔类型为false,整数类型为0,浮点数类型为0.0,字符串类型为"",指针、函数、接口、切片、通道和映射类型为nil。

Playground示例

关于nil接口和错误的一些信息也可以在Go FAQ为什么我的nil错误值不等于nil?中找到。

英文:

This is due to type safety. nil is actually the value of uninitialized variables in Go. The nil values for slices, maps, functions, channels, pointers and interfaces are not the same type, and not comparable. See The language spec for more details.

EDIT: As pointed out by @newacct the correct technical term for this is the "zero value" for the type:

>>When memory is allocated to store a value, either through a declaration or a call of make or new, and no explicit initialization is provided, the memory is given a default initialization. Each element of such a value is set to the zero value for its type: false for booleans, 0 for integers, 0.0 for floats, "" for strings, and nil for pointers, functions, interfaces, slices, channels, and maps.

Playground example

There is also some information regarding nil interfaces and errors at Why is my nil error value not equal to nil? in the Go FAQ.

答案3

得分: 8

在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要求显式指定类型。

英文:

All variables in Go need to have a type. Using := operator infers the type from type of right-side expression.

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

For pretty much any expression, its type is unambigous, due to needing to explicitly specify the type somewhere - or in case of number literals, having a default when unspecified. The only exception to this rule is nil.

n := nil // var n ???

nil is a valid value for the following.

  • Pointers
  • Unsafe pointers
  • Interfaces
  • Channels
  • Maps
  • Slices
  • Functions

There isn't a good default for a type when an user types nil, so instead Golang rejects this requiring an explicit type specification.

答案4

得分: 6

没有typed-nil,你就不能在:=短赋值语句中使用nil值。

a := nil // 错误:使用了未类型化的nil
b := error(nil) // 正确

它同样可以实现以下一行代码:

result, err := "一个好的结果", error(nil)

在某些情况下,像上面这样写可能会提供一些方便。


然而,请注意,nil不是一个关键字或字面量——Go语言没有内置或标准的typed-nil值。Typed-nil只存在于以下情况的结果中:

  • 使用默认(“零值”)初始化声明可为空值的类型变量
  • nil(直接或间接地)赋值给一个有类型的值
  • nil标识符转换为某种类型(如上面的示例所示)。

这里有一个关于typed nil和接口的微妙之处的视频片段:GopherCon 2015: Kevin Cantwell - What Could Go Wrong?

英文:

Without typed-nil, you couldn't use the short assignment statement := with the nil value.

a := nil // Error: use of untyped nil
b := error(nil) // OK

It, likewise, enables the following one-liner:

result, err := "A good result", error(nil)

Writing something like the above may provide some convenience on occasion.


Note, however, that nil is not a keyword or a literal -- and Go does not have a built-in or standard typed-nil value. Typed-nil exists only as the result of one of the following:

  • declaring a nillable typed variable with default ("zero value") initialization
  • assigning nil (directly or indirectly) to a typed value
  • casting the nil identifier to a type (as shown in the examples above).

Here's a clip about subtleties with typed nils and interfaces: GopherCon 2015: Kevin Cantwell - What Could Go Wrong?

huangapple
  • 本文由 发表于 2013年11月4日 11:53:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/19761393.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定