明天是《有个小问题》系列第一期,咱们一起先来看看 Go 语言标准中对于零值的规定。

当通过申明或调用 make 或 new 分配内存来存储一个值时,如果没有提供显式初始化,内存会被赋予一个默认的初始化。这种值的每一个元素都被设置为其类型的零值:布尔值为 false ,整数为 0 ,浮点数为 0.0 ,字符串为 "",指针、函数、接口、切片、 Channel 和 Map 为 nil 。这种初始化是以递归形式进行的,例如,如果没有指定值,构造数组中的每个元素的字段都会被清零。

前言

对于这种总是将一个值设置为已知默认值的属性对于程序的安全性和正确性是很重要的,同时也能够使程序看起来更简略更紧凑

这就是 Go 编程者所说的 “给你的代码构造一个有用的零值”。

例子1

上面是一个应用 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()}

例子2

另一个有用的零值类型的例子是 bytes.Buffer。能够不进行显式初始化就开始读取或写入,请留神,io.Copy 须要一个 io.Reader 作为它的第二个参数,所以咱们须要传递一个指向 b 的指针。

package mainimport (    "bytes"    "io"    "os")func main() {    var b bytes.Buffer    b.Write([]byte("Hello world"))    io.Copy(os.Stdout, &b)}

对于切片来说它们的零值是 nil。这意味着你不须要显式地创立一个切片,你能够间接申明它。

package mainimport (    "fmt"    "strings")func main() {    // s := make([]string, 0)    // s := []string{}    var s []string    s = append(s, "Hello")    s = append(s, "world")    fmt.Println(strings.Join(s, " "))}
留神:var s []string 与下面两行正文相似,但不完全相同。这两种初始化切片零值还是有区别的。上面的代码输入 false
package mainimport (    "fmt"    "reflect")func main() {    var s1 = []string{}    var s2 []string    // output: false    fmt.Println(reflect.DeepEqual(s1, s2))}

例子3

nil 指针的零值还有一种比拟实用的用法是,对具备 nil 值的类型调用办法,能够用来简略地提供默认值。

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())}

对于

关注博客看更多《有个小问题系列》