常量

Golang里的constants就是constants,在编译时创建。常量可以是这几种: numbers, characters (runes), strings or booleans。因为是在编译时处理的,所以常量的值必须是编译器可以搞定的,比如1,”abc”,以及 len(“abc”)。

注意最后这种也是可以的。

和变量不同,常量可以定义了,但是不用为什么?因为下面要用常量来定义枚举,谁能保证所有枚举就一定会用到呢?

package main
import "fmt"
func main() {
    const xxx = 123
    fmt.Println(xxx)

    const xx2 = "abc"
    fmt.Println(xx2)

    const xx3 = len("abc")
    fmt.Println(xx3)

    var x = 123
    const xx4 = unsafe.Sizeof(&x)
    fmt.Println(xx4)
}

输出

$ go run constants.go
123
abc
3
8

但像 math.Sin(math.Pi/4) 这种就不行了,因为编译器执行的时候没办法去调用runtime的math包。

枚举

golang使用iota来实现枚举。itoa可以定义在表达式里,而且表达式可以隐式重复,因此golang的枚举可以定义的非常花。

举个effective go的例子。

package main
import (
    "fmt"
)

type Byte float64
const (
    _ = iota
    KB Byte = 1 << (10*iota)    //iota自动+1,此时值为2,即 1 << (10*2)
    MB    //表达式自动重复, 1 << (10*iota)  即 1 << (10*3)
    GB    //...
    TB
    PB
    EB
    ZB
    YB
)

func (b Byte) String() string {
    switch {
        case b > YB:
            return fmt.Sprintf("%.2fYB", b/YB)
        case b > ZB:
            return fmt.Sprintf("%.2fZB", b/ZB)
        case b > EB:
            return fmt.Sprintf("%.2fEB", b/EB)
        case b > PB:
            return fmt.Sprintf("%.2fPB", b/PB)
        case b > TB:
            return fmt.Sprintf("%.2fTB", b/TB)
        case b > GB:
            return fmt.Sprintf("%.2fGB", b/GB)
        case b > MB:
            return fmt.Sprintf("%.2fMB", b/MB)
        case b > KB:
            return fmt.Sprintf("%.2fKB", b/KB)
    }
    return fmt.Sprintf("%.2fB", b)

}
func main() {
    var x Byte
    x = 1024*1024*1024 * 15
    fmt.Println(x)
    x = 1024*1024*1024*1024*1024 * 42
    fmt.Println(x)
}

iota很魔幻,编译器看到iota会自动给当前作用域下的自动+1,且表达式自动重复。

上面代码输出的结果如下。

$ go run iota.go
15.00GB
42.00PB

没找到iota的实现,应该比较有意思。

为什么是iota这个词呢?据说iota是一个雅典字符,表示求和算法中的迭代器。

iota是有坑的,要小心。

我们注意到,iota能够自动inc,inc的规则是作用域内每行+1。

看这个例子。

package main
import "fmt"
const (
    A, B int = iota, iota+1
    _, _
    C, D
    E int = iota+10
)
func main() {
    fmt.Println(A, B, C, D, E)
}

输出的是这样的。

$ go run iota2.go
0 1 2 3 13

显然iota是按行递增的,即使每行定义了2个变量。

Ref: