Go|Go 的零值有什么用(看看这 4 个场景)

大家好,我是煎鱼。
前文给大家分享了《10+ 条 Go 官方谚语,你知道几条?》,今天进一步讲讲第 5 条谚语 Make the zero value useful(让零值变得有用),看看里面想的是什么意思。
背景 Go 语言中有一个有些特殊的概念,叫做零值。许多转语言的同学经常会弄混淆,一开始会不适应。
代码如下:

func main() { var i int var f float64 var b bool var s string fmt.Printf("%v %v %v %q\n", i, f, b, s) }

输出结果:
0 0 false ""

这会导致大家在定义各种数据库字段时比较纠结,又会说 Go 这零值,例如:整形的零值 0,跟数据库里的 0 枚举值冲突。又或是做入参判断时怎么区别开?
一时半会想不明白,为什么 Go 要定义这个零值来增加复杂度?
有什么用 官方诠释
Go 核心团队的 @Dave Cheney 在《What is the zero value, and why is it useful?》中对零值进行了详细的阐释。
将一个值设置为已知默认值的特性,对于程序的安全性和正确性非常重要。可以使你的 Go 程序更加简单和紧凑。这就是 Go 程序员常说的 "给你的结构一个有用的零值"。
官方案例
以下是 Go 官方给出的几个零值的例子,非常具有代表性。分别是:
  • sync.Mutex。
  • byte.Buffer。
  • nil func。
Sync.Mutex sync.Mutex 被设计为无需显式初始化就可以使用,可以实现这个功能的原因是 sync.Mutex 包 含两个未导出的整数字段。
用大白话讲,就是由于零值的存在,只要声明了 sync.Mutex,这些字段就会被设置为 0(值会被初始化)。
因此可以无需显式初始化就可以开箱即用。
如下代码:
package mainimport "sync"type MyInt struct { mu sync.Mutex val int }func main() { var i MyInt// i.mu is usable without explicit initialisation. i.mu.Lock() i.val++ i.mu.Unlock() }

Byte.Buffer 因为有零值的存在,bytes.Buffer 在进行写入或读取的操作时,都不需要人为的进行明确的初始化。也能做到很好的开箱即用。
如下代码:
package mainimport "bytes" import "io" import "os"func main() { var b bytes.Buffer b.Write([]byte("Hello world")) io.Copy(os.Stdout, &b) }

注:io.Copy 需要一个 io.Reader 作为它的第二个参数,所以我们需要传递一个指向 b 的指针。
Slices 【Go|Go 的零值有什么用(看看这 4 个场景)】在 slices 的定义中,它的零值是 nil。这意味着你不需要显式定义一个 slices,只需要直接声明它,就可以使用了。
如下
package mainimport "fmt" import "strings"func main() { // s := make([]string, 0) // s := []string{} var s []strings = append(s, "Hello") s = append(s, "world") fmt.Println(strings.Join(s, " ")) }

Nil func 你可以在有 nil 值的类型上调用方法,这也是零值作为缺省值的作用之一。
这个场景,甚至一度让许多 Go 程序员以为是 BUG,我还专门写过文章。这是可行,其实都是零值的延伸出来的用法。
如下代码:
package mainimport "fmt"type Config struct { path string }func (c *Config) Path() string { if c == nil { return "/usr/home" } return c.path }func main() { var c1 *Config var c2 = &Config{ path: "/export", } fmt.Println(c1.Path(), c2.Path()) }

总结 零值,在 Go 里虽然是一个缺省值。但你它本质上不仅仅是一个缺省,它还为此在许多程序里的应用场景提供了不少的便捷特性,甚至是隐晦的功能。
希望对你对零值的理解有进一步的帮助!
Go 图书系列
  • Go 语言入门系列:初探 Go 项目实战
  • Go 语言编程之旅:深入用 Go 做项目
  • Go 语言设计哲学:了解 Go 的为什么和设计思考
  • Go 语言进阶之旅:进一步深入 Go 源码
更多阅读
  • Go 想要加个箭头语法,这下更像 PHP 了!
  • Go 错误处理新思路?用左侧函数和表达式

    推荐阅读