前言

当分配内存来存储一个类型的值时,它会被赋予该类型的默认值。 所以在 golang 中当通过声明或 new 出来的变量都会分配存储空间,而这些没有显式初始化都会给它一个默认值,而这个默认值就是零值。

零值

所有类型的零值如下:

  • Boolean:false
  • Integer:0
  • Float:0.0
  • String:“”

接口、切片、通道、映射、指针和函数:无
对于数组或者 struct,如果未指定值,则数组或结构的元素将其字段归零。

type Person struct {
    name string
    age int
    next *Person
}

fmt.Println([2]Person{}) 
// 输出结果:{"" 0 <nil>} {"" 0 <nil>

那么零值在我们项目中发挥着什么样的作用呢?

Slice 零值

切片 slice 的零值为 nil,因此我们可以使用它来检查切片是否为空。

var s []int
if s == nil {
  fmt.Println("slice is empty")
}

但需要注意,长度为零的 Slice 值与零Slice不同。nil 的长度为零,但是使用make([]T, 0) 创建的切片的长度为零但不是 nil

var s1 []int // s1 是 nil
var s2 = []int{} // s2 不是nil ,而是长度为0的 Slice
var s3 = make([]int,0) //s3 不是nil ,而是长度为0的 Slice

如果Slice的值是nil正准备使用,所以无需检查是否是nil

sync.Mutex 零值

sync.Mutex 包含两个未导出的整数字段。 多亏了零值,只要声明了 sync.Mutex,这些字段就会被设置为 0

type Counter struct {
   mu    sync.Mutex
   count int
}
func (c *Counter) Inc() {
   c.mu.Lock()
   defer c.mu.Unlock()
   c.count++
}
func main() {
   var c Counter
   c.Inc()
   fmt.Println(c.Value())
}

从功能的角度来看,互斥锁的零值是解锁的。 所以,我们可以使用互斥锁的零值来创建一个新的计数器。
这是一个方便的属性。 这意味着我们可以创建一个互斥体并开始使用它,而不必担心它是否被锁定。
byte.Buffer 零值
bytes.Buffer 的零值是一个可以使用的空缓冲区,因此我们可以使用它来累积数据,然后将其读出。

var b bytes.Buffer
b.Write([]byte("Hello"))
b.Write([]byte(" "))
b.Write([]byte("World"))

fmt.Println(b.String()) // 将会输出结果 Hello World

sync.WaitGroup 零值

WaitGroup 的零值是有效的WaitGroup。 我们可以直接使用它来做并发任务而不用初始化它。

var wg sync.WaitGroup // 声明的 WaitGroup 值是零值

for i:= 1; i<=10; i++ {
    wg.Add(1)
    go func(i int){
        defer wg.Done()
        fmt.Println("No: ", i)
    }(i)
}
wg.Wait()

指针零值

指针的零值是 nil。您对于具有nil值的类型上调用方法时,对nil 进行判断返回默认值。

type Person struct {
    Name string
    sex int
}

func (p *Person) isBoy() bool {
   if p == nil {
        return false
    }
    return p.sex==2
}

链接:https://juejin.cn/post/7158464230595756046