Go 零值和空值的判断问题

发布时间:2025-05-19 01:29:23 作者:益华网络 来源:undefined 浏览量(0) 点赞(0)
摘要:来源:脑子进煎鱼了 大家好,我是煎鱼。 前段时间分享了《Go 将增加内置的零值标识符 zero!》的新预定义标识符 zero。 对应的签名如下://zeroisapredeclaredidentifierrepresentin

来源:脑子进煎鱼了

大家好,我是煎鱼。

前段时间分享了《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 intvar b boolvar c stringfunc main()

 {

 fmt.Printf("%+v\n", a) // 0 fmt.Printf("%+v\n", b) // false fmt.Printf("%+v\n", c) // ""

}

复合类型

var a []intvar b map[string]intvar c [7]intvar d *intvar g chan intvar

 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 *intvar b *boolvar c *stringfunc main()

 {

 if a == nil

 {

  fmt.Print("煎鱼"

)

 }

 if b == nil

 {

  fmt.Print("进"

)

 }

 if c == nil

 {

  fmt.Print("脑子了"

)

 }

}

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

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

var a []intvar b map[string]intvar g chan intvar c *[7]intvar d *intvar

 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:}

煎鱼

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

如果是为空字符串:

s := `{

  "name"""

 }`

解析后输出的结果为:

p: {Name:0xc000096380 Age:}

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

但也引入了一个麻烦的点,就是在获取值时需要使用 *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)中零值是官方的规范约定,改变的可能性也很低了。个人感觉核心团队新增判别方式或优化的可能性比较低。

大家平时除了使用指针和预定义非零值的枚举值外,还会用什么方法来判别零值和空值呢,也欢迎大家分享你的看法!

二维码

扫一扫,关注我们

声明:本文由【益华网络】编辑上传发布,转载此文章须经作者同意,并请附上出处【益华网络】及本页链接。如内容、图片有任何版权问题,请联系我们进行处理。

感兴趣吗?

欢迎联系我们,我们愿意为您解答任何有关网站疑难问题!

您身边的【网站建设专家】

搜索千万次不如咨询1次

主营项目:网站建设,手机网站,响应式网站,SEO优化,小程序开发,公众号系统,软件开发等

立即咨询 15368564009
在线客服
嘿,我来帮您!