Go 语言
声明、类型、语句与控制结构
零值可用类型

零值可用类型

Go 谚语:保持零值可用。

在 Go 中,零值是一种保底机制,用于处理各种异常情况。例如,如果你声明了一个变量但还没有给它赋值,那么它的值就是零值(zero value)。零值机制保证了变量总是可以访问到的,这样就不会出现未初始化的变量。

Go 类型的零值

Go 语言中,每种类型都有自己的零值,下面是一些常见类型的零值:

  • 所有整数类型(包括 complex64/128):0
  • 浮点类型: 0.0
  • 字符串类型: ""
  • 布尔类型: false
  • 切片(slice)、function、指针、interfacechannelmapnil

另外,Go 语言中还有一些特殊类型的零值:

  • error 类型:nil
  • 数组类型:每个元素都是对应类型的零值
  • 结构体类型:每个字段都是对应类型的零值

零值可用

零值可用的意思是,当你没有初始化一个变量时,这个变量的值就是零值。这样的话,你就不用担心未初始化的变量会导致程序崩溃了。

Go 语言有很多零值可用的例子:

切片例子:

var s []int
s = append(s, 1)
s = append(s, 2)
s = append(s, 3)
println(s) // [1 2 3]

我们声明了一个 []int的切片,其零值为 nil,切片类型具有零值可用,不需要显示初始化,就可以使用 append() 函数向切片中添加元素。

更好的零值可用的例子就是 sync.Mutexbytes.Buffer

var mu sync.Mutex
mu.Lock()
defer mu.Unlock()
 
var b bytes.Buffer
b.Write([]byte("Hello "))

这里我们声明了一个 sync.Mutex 类型的变量 mu,其零值为 nil,但是我们仍然可以调用 mu.Lock()mu.Unlock() 方法,这是因为 sync.Mutex 类型具有零值可用。

另外,我们声明了一个 bytes.Buffer 类型的变量 b,因为 bytes.Buffer 的结构体中用于存储数据的字段 buf 是切片类型,其支持零值可用,所以我们仍然可以调用 b.Write() 方法。

一些限制

零值可用的切片类型,只能用于 append() 函数,不能用于索引操作,否则会导致程序崩溃。

var s []int
s[0] = 1 // panic: runtime error: index out of range
s = append(s, 1)

map 这种原生类型也没有提供零值可用的支持:

var m map[string]int
m["go"] = 1 // panic: assignment to entry in nil map
 
m1 := make(map[string]int)
m1["go"] = 1

注意避免值复制

var mu sync.Mutex
mu1 := mu // 错误,sync.Mutex 类型不支持值复制
foo(mu) // 错误,sync.Mutex 类型不支持值复制

应该通过指针的方式来传递 sync.Mutex 类型的值:

var mu sync.Mutex
foo(&mu)