2.4 nil的语义

什么?nil是一种数据结构么?为什么会讲到它,没搞错吧?没搞错。不仅仅是Go语言中,每门语言中nil都是非常重要的,它代表的是空值的语义。

在不同语言中,表示空这个概念都有细微不同。比如在scheme语言(一种lisp方言)中,nil是true的!而在ruby语言中,一切都是对象,连nil也是一个对象!在C中NULL跟0是等价的。

按照Go语言规范,任何类型在未初始化时都对应一个零值:布尔类型是false,整型是0,字符串是"",而指针,函数,interface,slice,channel和map的零值都是nil。

interface

一个interface在没有进行初始化时,对应的值是nil。也就是说var v interface{}

此时v就是一个nil。在底层存储上,它是一个空指针。与之不同的情况是,interface值为空。比如:

var v *T
var i interface{}
i = v

此时i是一个interface,它的值是nil,但它自身不为nil。

Go中的error其实就是一个实现了Error方法的接口:

type error interface {
    Error() string
}

因此,我们可以自定义一个error:

type Error struct {
    errCode uint8
}
func (e *Error) Error() string {
        switch e.errCode {
        case 1:
                return "file not found"
        case 2:
                return "time out"
        case 3:
                return "permission denied"
        default:
                return "unknown error"
         }
}

如果我们这样使用它:

func checkError(err error) {
    if err != nil {
        panic(err)
    }
}
var e *Error
checkError(e)

e是nil的,但是当我们checkError时就会panic。请读者思考一下为什么?

总之,interface跟C语言的指针一样非常灵活,关于空的语义,也跟空指针一样容易困扰新手的,需要注意。

string和slice

string的空值是"",它是不能跟nil比较的。即使是空的string,它的大小也是两个机器字长的。slice也类似,它的空值并不是一个空指针,而是结构体中的指针域为空,空的slice的大小也是三个机器字长的。

channel和map

channel跟string或slice有些不同,它在栈上只是一个指针,实际的数据都是由指针所指向的堆上面。

跟channel相关的操作有:初始化/读/写/关闭。channel未初始化值就是nil,未初始化的channel是不能使用的。下面是一些操作规则:

  • 读或者写一个nil的channel的操作会永远阻塞。
  • 读一个关闭的channel会立刻返回一个channel元素类型的零值。
  • 写一个关闭的channel会导致panic。

map也是指针,实际数据在堆中,未初始化的值是nil。

links

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8