持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第23天,点击查看活动详情
前言
刚接触Go看别人代码的时候,发现全是if xx != nil, 一脸懵,nil到底是个啥?,其实Go 里面很多类型使用 nil 来赋值和做条件判断,Go 里面 nil 是一个关键字?还是类型?还是变量?总是混淆记不住;今天就来写一点自己对于nil的理解。需要的朋友可以参考以下内容,希望对大家有帮助。
nil是个啥?
首先,我们根据源代码看一下官方是怎么定义的nil
// 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 type
// Type is here for the purposes of documentation only. It is a stand-in
// for any Go type, but represents the same type for any given function
// invocation.
type Type int
从类型定义我们可以得到: 本质上是一个 Type类型的变量而已;而Type类型是基于int定义出来的一个新类型;
根据注释我们可以得到:nil是一个预先声明的标识符,表示指针、通道、函数、接口、映射或切片类型的零值,并不是GO 的关键字之一。
默认值nil
在go语言中:
- 布尔类型的零值(初始值)为 false
- 数值类型的零值为 0
- 字符串类型的零值为空字符串""
除此之外其它类型的默认值为nil,nil可以代表下面这些类型的零值:
- 指针类型(包括unsafe中的)
- map类型
- slice类型
- function类型
- channel类型
- interface类型
nil常见的用法
_,err := funcName(xxx)
//判断err是否等于nil
if err!=nil{
fmt.Println(err)
}
nil使用注意事项
不同类型的nil值占用的内存大小可能是不一样的
一个类型的所有的值的内存布局都是一样的。nil也不例外。nil的大小一致与同类型中的非nil类型的值的大小一样大。但是不同类型的nil值的大小可能不同。
package main
import (
"fmt"
"unsafe"
)
func main() {
var sInt []int = nil
fmt.Println(unsafe.Sizeof(sInt)) // 24
var i interface{} = nil
fmt.Println(unsafe.Sizeof(i)) // 16
var p *struct{} = nil
fmt.Println(unsafe.Sizeof(p)) // 8
}
不同类型 nil 的指针是一样的
//不同类型的nil指针是一样的
package main
import (
"fmt"
)
func main() {
var arr []int
var num *int
fmt.Printf("%p\n", arr) //0x0
fmt.Printf("%p", num) //0x0
}
不同类型的 nil 是不能比较的
可以将不可比较类型的空值直接与 nil 标识符进行比较,但是不同类型的 nil 是不能比较的。
package main
import "fmt"
func main() {
var arr []int
var num []int
//可以直接跟nil比较
if arr == nil {
fmt.Println("arr is nil")
}
//两个不同类型的nil是无法比较的,报错。
if arr == num {
fmt.Println("arr == num")
}
}
总结
Go语言中nil是一个预先声明的标识符,是一个变量,表示指针、通道、函数、接口、映射或切片类型的零值,并不是GO 的关键字之一。
nil只能赋值给指针、channel、func、interface、map或slice类型的变量 (非基础类型) 否则会引发 panic。