Go语言基础:使用nil的注意事项

定义

nil不是golang的关键词,只是一个变量名。定义在buildin/buildin.go

// nil 是一个预先声明的标识符,表示指针、通道、函数、接口、映射或切片类型的零值。
var nil Type // 类型必须是指针、通道、函数、接口、映射或切片类型
​
// Type在这里仅用于文档目的。它是任何 Go 类型的替代品,但代表任何给定函数调用的相同类型。
type Type int
复制代码

我们甚至可以自己声明一个名为nil的变量来将其覆盖掉,当然,这是不推荐的。

从定义的注释中可以看出,nil用来表示指针、通道、函数、接口、映射或切片类型的零值

零值

在golang声明一个变量的时候,我们如果没有对其进行显式初始化,那么该变量将会被赋予一个零值。

数据类型 零值
布尔类型 false
数值类型 0
字符串 ""
引用类型 nil

结构体数组会递归初始化其字段或者元素,其初始值取决于元素或字段。

Panic

给空指针赋值

var i *int
*i = 1    // panic
复制代码

解决办法

给空指针分配一块内存即可

var i *int
i = new(int)
*i = 1    // panic
复制代码

从空指针取值

var i *int
a := *i    // panic
复制代码

解决办法

赋值前,判断该指针是否为空

var i *int
var a int
if i != nil {
    a = *i
}
// a = 0
复制代码

接口类型

golang中有一个很出名的nil != nil的例子:

var x *int
var y interface{}
fmt.Println(x == nil)    // true
fmt.Println(y == nil)    // true
fmt.Println(x == y)      // false
复制代码

这个结果跟interface的实现原理有关,这里不详细展开解释,简单来说,一个interface需要通过typevalue两个属性来确定值。

给上面的代码加上注释,就清晰了:

var x *int            // type = *int, value = nil
var y interface{}     // type = nil, value = nil
fmt.Println(x == y)   // (*int, nil) == (nil, nil) => false
复制代码

错误处理的坑

type MyError struct {}
​
func (m MyError) Error() string { return "my error" }
​
func test() error {
   var err *MyError
   return err
}
​
func main() {
   err := test()
   fmt.Println(err)           // <nil>
   fmt.Println(err == nil)    // false
}
复制代码

我们会发现,直接输出err的值时,的确是<nil>。将其与nil相比较时,得到的结果又是false

有了上面的例子,我们就知道,原来是在test()中改变了errtype,导致最终判断结果不符合预期。

猜你喜欢

转载自juejin.im/post/6999169328558014501