nil
约 539 字大约 2 分钟
2024-05-19
nil 是Go语言中的一个变量(builtin/builtin.go),是预先声明的标识符,用来作为引用类型变量的零值。
// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice typenil 与 pointer、channel、func、map、slice比较
对于指针类型(pointer)变量,只有其未指向任何对象时候,才能等于 nil:
func main() {
var p *int
println(p == nil) // true
a := 100
p = &a
fmt.Println(p == nil) // false
}对于channel、func、map、slice,只有 var t T 或者手动赋值为nil时,才等于nil
func main() {
// slice
var s []int // nil slice s.array == nil
fmt.Println(s == nil) // true
s = make([]int, 0) // empty slice; s.array == &zerobase
fmt.Println(s == nil) // false
// map
var m map[int]int
fmt.Println(m == nil) // true
m = make(map[int]int)
fmt.Println(m == nil) // false
// channel
var ch chan int
fmt.Println(ch == nil) // true
ch = make(chan int)
fmt.Println(ch == nil) // false
// 函数
var fn func()
fmt.Println(fn == nil) // true
fn = func() {}
fmt.Println(fn == nil) // false
}zerobase是 Go runtime 提供的全局固定地址,用作所有零字节分配的起始基址,保证即使长度为 0,底层指针仍合法且非 nil
nil 与 接口比较
接口类型变量根据是否包含方法,分为 eface(空接口) 和 iface(非空接口) 两种形式,但它们在语义上都可以抽象为包含两个基础属性:
- Type:接口中保存的动态类型信息
- 在 eface 中对应 *_type
- 在 iface 中由 *itab 间接表示
- Value:接口中保存的动态值,即底层数据指针data unsafe.Pointer
接口是否为 nil,取决于 Type 和 Value 是否同时为 nil,而不是仅仅取决于 Value
func main() {
var p *int = nil
var i interface{} // (_type=nil, data=nil)
fmt.Println(i == nil) // true
var i2 interface{} = p // (_type=*int, data= nil)
fmt.Println(i2 == nil) // false _type不为nil
fmt.Println(i2 == i) // false _type不一致
fmt.Println(p == i) // false 当变量和接口比较时候,会隐式将其转换成接口。所以结果跟上面一样
var i3 interface{} = (*interface{})(nil) // (_type=*interface{}, data=nil)
fmt.Println(i3 == nil) // false
var i4 interface{} = (interface{})(nil) // (_type=nil, data=nil)
fmt.Println(i4 == nil) // true
}