70

Golang: 常量、枚举,以及魔幻的iota

 5 years ago
source link: http://ieevee.com/tech/2018/07/04/go-constants.html?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

常量

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:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK