Golang 中所有没有显示申明值的变量,都会被初始化为默认值,规范中定义的默认值为:
- 所有整型类型:
0
- 浮点类型:
0.0
- 布尔类型:
false
- 字符串类型:
""
- 指针、interface、切片(slice)、channel、map、function:
nil
对于一些类型,虽然默认值为 nil
,但可以在不初始的情况下进行调用,这种特性被称作零值可用,例如下面这个例子。
var zeroSlice []int
zeroSlice = append(zeroSlice, 1)
zeroSlice = append(zeroSlice, 2)
zeroSlice = append(zeroSlice, 3)
fmt.Println(zeroSlice) // 输出:[1 2 3]
这个例子中,并没有使用 make([]int)
来显式的初始 zeroSlice
,但是我们仍能直接对其使用 append
方法。
另外两个标准库的例子是 bytes.Buffer
和 sync.Mutex
。
var mu sync.Mutex
mu.Lock()
mu.Unlock()
var b bytes.Buffer
b.Write([]byte("Effective Go"))
当然,并不是所有的类型和方法都适用,其实原理也比较简单,Golang 调用方法时会自动的转换指针。对于上面例子中,Mutex
的 Lock
, Unlock
和 Buffer
的 Write
都定义在指针上,调用是会自动切换,这样在方法体内可以直接判断如果传入指针为 nil
,则对其再进行初始化操作就可以了。比如下面这个例子:
func (a *TCPAddr) String() string {
if a == nil {
return "<nil>"
}
ip := ipEmptyString(a.IP)
if a.Zone != "" {
return JoinHostPort(ip+"%"+a.Zone, itoa(a.Port))
}
return JoinHostPort(ip, itoa(a.Port))
}
这里还透露了 Golang runtime 的一个实现细节,对于 var b bytes.Buffer
这个变量,runtime 不仅存储了 b
这个变量的值,也存储了其类型对应方法的函数表。