你真的会处理 go 中的 nil 吗?

2023-12-13 18:00:07

对于下面这段代码,我们知道?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

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,不要用指针类型的零值

技术前沿拓展

前端开发,你的认知不能仅局限于技术内,需要发散思维了解技术圈的前沿知识。细心的人会发现,开发内部工具的过程中,大量的页面、场景、组件等在不断重复,这种重复造轮子的工作,浪费工程师的大量时间。

介绍一款程序员都应该知道的软件?JNPF 快速开发平台,很多人都尝试用过它,它是功能的集大成者,任何信息化系统都可以基于它开发出来。

这是一个基于 Java Boot/.Net Core 构建的简单、跨平台快速开发框架。前后端封装了上千个常用类,方便扩展;集成了代码生成器,支持前后端业务代码生成,实现快速开发,提升工作效率;框架集成了表单、报表、图表、大屏等各种常用的 Demo 方便直接使用;后端框架支持 Vue2、Vue3。如果你有闲暇时间,可以做个知识拓展。

文章来源:https://blog.csdn.net/fefdfg/article/details/134975224
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。