golang中的nil

747 阅读2分钟

摘要

Go中的nil只能用来表示指针、接口、通道、映射、切片和函数类型的零值,非以上6种类型的是不能使用nil表示的。

正文

nil的定义

Go 中的nil与其它语言中的null是一样的吗?

Java或其他编程语言背景的话,你可能认为它们是一样的,但其实它们部分相同但又有些不同。

nilGo 中预先声明的标识符,表示指针、接口、通道、映射、切片和函数类型的零值。 nil是指针和接口的零值,未初始化的指针和接口将为nil。这是否意味着字符串不能为nil? 是的! 字符串不符合上述任何一种类型因此不能被赋值为 nil

给不指定类型的变量赋值nil

那我用nil做一个短声明会怎样呢?

a := nil

这将触发一个编译时错误use of untyped nil,因为 nil 是非类型化(untyped)的,并且是唯一没有默认类型的非类型化值,编译器不知道它必须分配给a的类型。

接下来,让我们尝试为限定类型(指针)赋值

var *a int = nil

上述代码会按我们期望的那样成功运行。

函数返回nil

如果我尝试从函数返回 nil 会怎样?

package main

import "fmt"

type A struct {
   str string
}
func main() {
   s := getA()
   fmt.Println(s.str) // This will crash
}
func getA() *A {
   return nil // This WILL compile
}

上面的程序会因为这个错误而恐慌(panic)。

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x1092534]

但它不是一个编译时错误,因为我们返回了一个 nil 指针,指针正是 nil的限定类型.

两个nil值能互相比较吗

让我们看看这两个代码片段

var m []int = nil
var n []int = nil
if m == n {
   fmt.Println("equal")
}

这将会产生一个编译时错误:

invalid operation: m == n (slice can only be compared to nil)

我们再看下一个

var i someIntf = nil
var j someIntf = nil
if i == j{
fmt.Println("equal")
}

上面代码可以工作,并且打印出equal

为什么会这样?

因为在 Go 中,mapslicefunction 类型不支持比较。不可比较类型的两个nil 值是不允许比较的。 但是不可比较的类型可以与裸 nil 标识符进行比较。

var m []int = nil
var n []int = nil
if m == nil &&  n == nil {
   fmt.Println("both are nil")
}

参考

Nil in Golang