你会处理 go 中的 nil 吗

对于下面这段代码,我们知道 i 实际上的值就是 nil,所以 i == nil 会生效

func main() {
   
  var i *int = nil
  if i == nil {
   
    fmt.Println("i is nil") // i is nil
  }
}

现在换一种写法,我们将 i 的类型改成 interface{},i == nil 依然会生效

func main() {
   
  var i interface{
   } = nil
  if i == nil {
   
    fmt.Println("i is nil") // i is nil
  }
}

我们接着改造,将

i == nil 的逻辑封装成函数 IsNil
go复制代码func IsNil(i interface{
   }) {
   
  if i == nil {
   
    fmt.Println("i is nil")
  }
}
func main() {
   
  var i *int = nil
  IsNil(i)
}

居然发现 IsNil 中的 i == nil 不生效了
这是为什么呢?
因为对于 interface{} 类型的值来说,如果要判断它是 nil,必须同时满足 type T 和 value V 都是 nil 才行
可以用 reflect 中的 TypeOf 和 ValueOf

var i *int = nil
fmt.Println(reflect.TypeOf(i), reflect.ValueOf(i)) // *int  <nil>

var i interface{
   } = nil
fmt.Println(reflect.TypeOf(i), reflect.ValueOf(i)) // <nil> <invalid reflect.Value>

如果我们在函数中用 interface{} 作为参数的类型,表示并不代表参数就是 interface{} 类型,而是任意类型,调用时传入啥类型就是啥类型,如下代码

var i interface{
   } = 1
fmt.Println(reflect.TypeOf(i)) // int

var j interface{
   } = "hello"
fmt.Println(reflect.TypeOf(j)) // string

var k interface{
   } = nil
fmt.Println(reflect.TypeOf(k)) // nil

所以只有当我们传入的参数类型是 interface{},且 value 为 nil 时,i == nil 才会生效
否则其他情况都不会生效

func main() {
   
  var i interface{
   } = nil
  IsNil(i)  // i is nil
}
func IsNil(i interface{
   }) {
   
  if i == nil {
   
    fmt.Println("i is nil")
  }
}

这个坑可能会出现在返回 error 的函数中,比如下面这段代码
在函数 SomeThing 中提前定义了 myError,然后一系列的处理后,返回了 myError
后面的业务逻辑需要判断 err 是否为 nil

type MyError struct{
   }
func (me *MyError) Error() string {
   
  return "my error"
}
func SomeThing() error {
   
  var myError *MyError    // 默认初始化为 nil
  // ...
  return myError
}
func main() {
   
  err := SomeThing()
  fmt.Println(reflect.TypeOf(err), reflect.ValueOf(err)) // *main.MyError <nil>
  if err != nil {
        // 虽然没有返回,这里会被执行,因为 err 的类型不是 nil
    fmt.Println(err)
  }
}

从上面的代码我们看到,SomeThing 函数中定义的 myError 是 *MyError 类型,虽然返回了 nil,但是 err 的类型不是 nil,所以 err != nil 会生效,不符合预期
如果修改这个问题呢,当我们需要返回 nil 时,显示指明返回 nil,如下代码:

type MyError struct{
   }
func (me *MyError) Error() string {
   
  return "my error"
}
func SomeThing() error {
   
  var myError *MyError    // 默认初始化为 nil
  // ...
  return nil
}
func main() {
   
  err := SomeThing()
  fmt.Println(reflect.TypeOf(err), reflect.ValueOf(err)) // <nil> <invalid reflect.Value>
  if err != nil {
        // 这段代码不会被执行
    fmt.Println(err)
  }
}

总结:需要返回 nil 时,要显示返回 nil,不要用指针类型的零值

相关推荐

  1. 处理 go nil

    2023-12-19 16:56:03       33 阅读
  2. 【开发掉坑】go interface nil 判断

    2023-12-19 16:56:03       32 阅读
  3. 77.Gointerface{}判nil正确姿势

    2023-12-19 16:56:03       24 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-19 16:56:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-19 16:56:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-19 16:56:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-19 16:56:03       18 阅读

热门阅读

  1. 高德map点标记随zoom缩放位置不变

    2023-12-19 16:56:03       40 阅读
  2. Linux 硬链接和软链接

    2023-12-19 16:56:03       44 阅读
  3. 【Spring】Spring AOP

    2023-12-19 16:56:03       30 阅读
  4. 计时器plus

    2023-12-19 16:56:03       43 阅读
  5. el-table表格中数据过长如何使用省略号

    2023-12-19 16:56:03       46 阅读
  6. CDN的特点及意义?

    2023-12-19 16:56:03       42 阅读