摘要
Go中的nil只能用来表示指针、接口、通道、映射、切片和函数类型的零值,非以上6种类型的是不能使用nil表示的。
正文
nil的定义
Go 中的nil与其它语言中的null是一样的吗?
有Java或其他编程语言背景的话,你可能认为它们是一样的,但其实它们部分相同但又有些不同。
nil是 Go 中预先声明的标识符,表示指针、接口、通道、映射、切片和函数类型的零值。 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 中,map、slice 和 function 类型不支持比较。不可比较类型的两个nil 值是不允许比较的。
但是不可比较的类型可以与裸 nil 标识符进行比较。
var m []int = nil
var n []int = nil
if m == nil && n == nil {
fmt.Println("both are nil")
}