浅析Go中关于零值和空值判断的问题

 更新时间:2023年08月23日 14:27:54   作者:脑子进煎鱼了  
这篇文章主要是对零值和空值判断现状进行简单的梳理和分享,文中的示例代码讲解详细,对我们深入了解go语言有一定的帮助,感兴趣的小伙伴可以跟随小编一起学习一下

前段时间分享了《Go 将增加内置的零值标识符 zero!》的新预定义标识符 zero

对应的签名如下:

// zero is a predeclared identifier representing the zero value
// for array and struct types.
var zero Type

我原想着还是一个有一点点新改变。不过综合大家意见来看,由于只是针对数组(array)和结构体(struct),许多同学表示这个是比较鸡肋的。因为仍然无法很好的解决 Go 零值和空值的识别问题,大失所望。

本文是对零值和空值判断现状进行梳理和分享。

快速复习零值

基本类型

var a int
var b bool
var c string
func main() {
 fmt.Printf("%+v\n", a) // 0
 fmt.Printf("%+v\n", b) // false
 fmt.Printf("%+v\n", c) // ""
}

复合类型

var a []int
var b map[string]int
var c [7]int
var d *int
var g chan int
var p Person
type Person struct {
 Name string
 Age  int
}
func main() {
 fmt.Printf("%+v\n", a) // []
 fmt.Printf("%+v\n", b) // map[]
 fmt.Printf("%+v\n", c) // [0 0 0 0 0 0 0]
 fmt.Printf("%+v\n", d) // <nil>
 fmt.Printf("%+v\n", g) // <nil>
 fmt.Printf("%+v\n", p) // {Name: Age:0}
}

进行空值判断

在实际的 Go 业务应用中,我们需要对数据的零值和空值进行区分,以便于实现一些空值的业务逻辑处理。(初入门的同学经常在此踩坑)

常见的有两种做法。如下:

  • 在变量声明时,使用指针来处理,将其声明为指针类型。
  • 在定义变量缺省值时,错开类型的零值。例如:int 零值是 0,业务里字段缺省值定义为 1 和 2 等。

第一种是用的最多的,也是前文评论区大家有所提到的。对于基础类型,具体的代码示例如下:

var a *int
var b *bool
var c *string
func main() {
 if a == nil {
  fmt.Print("煎鱼")
 }
 if b == nil {
  fmt.Print("进")
 }
 if c == nil {
  fmt.Print("脑子了")
 }
}

输出结果:煎鱼进脑子了。

对于复合类型,也是一样的:

var a []int
var b map[string]int
var g chan int
var c *[7]int
var d *int
var p *Person

对于复合类型的一些值类型,由于零值有可能是程序赋的值,也有可能是真空值。因此同样需要加上指针,用于识别空值和零值。

在 Go 业务程序上,大家为了解决这个零值和空值的判别问题。会采取上述类似的方式去编写包和程序。

如下演示代码:

type Person struct {
 Name *string
 Age  *int
}
func main() {
 s := `{
  "name": "煎鱼"
 }`
 var p Person
 err := json.Unmarshal([]byte(s), &p)
 if err != nil {
  fmt.Println(err)
 }
 fmt.Printf("p: %+v\n", p)
 fmt.Println(*p.Name)
}

输出结果:

p: {Name:0xc00010c380 Age:<nil>}
煎鱼

可以看到所传入的 json 字符串并不包含 age 字段,因此其值为 nil。

如果是为空字符串:

s := `{
  "name": ""
 }`

解析后输出的结果为:

p: {Name:0xc000096380 Age:<nil>}

以此就可以实现空值和零值的有效区分,不再为此判别烦恼太多。

但也引入了一个麻烦的点,就是在获取值时需要使用 *p.Name 的方式。如果希望 “屏蔽” 这个用法,一般还会再做一次函数封装作为 Getter 的方法。

新增 zero 解决什么问题

显然我再回去看即将新加入的 zero 标识符时,会发现他能够成功 Go 的机缘是对零值的比较判断,而并非空值的原因。

zero 使用场景是:

if val == zero(MyType) {}

又或是:

func example[T any]() T {
  // do something that returns an error...
  if err != nil {
    return zero(T)
  }
  //...
}

这么一梳理,发现确实和我们想象中的有一定的差距。因为我们在实际的零值和空值的判断中,更需要的是对内部字段的数值判断例如:结构体里的某些字段,比较少是只对结构体本身做空值判断。

总结

今天根据大家热议的反馈,重新梳理了 Go 中零值和空值的现状和判断技巧。感觉本次 zero 的加入,真的是只加强了结构体和数组类型本身的零值判断,而没有针对空值的好手段。

综合来看,考虑到规范(SPEC)中零值是官方的规范约定,改变的可能性也很低了。个人感觉核心团队新增判别方式或优化的可能性比较低。

到此这篇关于浅析Go中关于零值和空值判断的问题的文章就介绍到这了,更多相关Go零值空值内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 手把手带你走进Go语言之循环语句

    手把手带你走进Go语言之循环语句

    在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句。一组被重复执行的语句称之为循环体,能否继续重复,决定循环的终止条件,本文给大家介绍的非常详细,跟着小编往下看吧
    2021-09-09
  • Kotlin编程基础语法编码规范

    Kotlin编程基础语法编码规范

    这篇文章主要为大家介绍了Kotlin编程条件控制示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • 一文带你掌握掌握 Golang结构体与方法

    一文带你掌握掌握 Golang结构体与方法

    在 Golang 中,结构体和方法是实现面向对象编程的重要组成部分,也是 Golang 的核心概念之一。在本篇文章中,我们将深入介绍 Golang 结构体与方法的概念、使用方法以及相关的编程技巧和最佳实践
    2023-04-04
  • Golang中的自定义函数类型详解

    Golang中的自定义函数类型详解

    在 Golang 中,type 关键字用于定义自定义类型,函数也是一种数据类型,因此可以使用 type 关键字来定义函数类型,本文就给大家详细介绍一下Golang中的自定义函数类型,需要的朋友可以参考下
    2023-07-07
  • golang双链表的实现代码示例

    golang双链表的实现代码示例

    这篇文章主要介绍了golang双链表的实现代码示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • Swaggo零基础入门教程

    Swaggo零基础入门教程

    swagger是一套基于OpenAPI规范构建的开源工具,使用RestApi。swagger-ui呈现出来的是一份可交互式的API文档,可以直接在文档页面尝试API的调用
    2023-01-01
  • 浅谈GoLang几种读文件方式的比较

    浅谈GoLang几种读文件方式的比较

    这篇文章主要介绍了浅谈GoLang几种读文件方式的比较,一般来说常用的有三种。使用Read加上buffer,使用bufio库和ioutil 库,非常具有实用价值,需要的朋友可以参考下
    2019-01-01
  • Go语言Seeker接口与文件断点续传实战教程

    Go语言Seeker接口与文件断点续传实战教程

    Go语言的io包中Seeker接口为大文件处理或需要随机访问的场景提供了强大的支持,本文通过具体案例详细介绍了Seeker接口的应用,包括随机访问大文件、断点续传等场景,以及如何使用Seeker接口进行有效的文件读写操作
    2024-10-10
  • Go代码检查的推荐工具及使用详解

    Go代码检查的推荐工具及使用详解

    这篇文章主要为大家介绍了Go代码检查的推荐工具及使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • 使用Golang Validator包实现数据验证详解

    使用Golang Validator包实现数据验证详解

    在开发过程中,数据验证是一个非常重要的环节,而golang中的Validator包是一个非常常用和强大的数据验证工具,提供了简单易用的API和丰富的验证规则,下面我们就来看看Validator包的具体使用吧
    2023-12-12

最新评论