Effective Go: 初始化(二)

125 阅读2分钟

这是我参与11月更文挑战的第22天,活动详情查看:2021最后一次更文挑战

常量(二)

在 Go 中,枚举常量是使用 iota 枚举器创建的。 由于 iota 可以是表达式的一部分,并且表达式可以隐式重复,因此很容易构建复杂的值集。

type ByteSize float64const (
    _           = iota // ignore first value by assigning to blank identifier
    KB ByteSize = 1 << (10 * iota)
    MB
    GB
    TB
    PB
    EB
    ZB
    YB
)

将诸如 String 之类的方法附加到任何用户定义类型的能力使得任意值可以自动格式化以进行打印。 尽管您会看到它最常应用于结构,但此技术对于标量类型也很有用,例如像 ByteSize 这样的浮点类型。

func (b ByteSize) 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)
}

表达式 YB 会打印为 1.00YB,而 ByteSize(1e13) 打印为 9.09TB。

这里使用Sprintf来实现ByteSize的String方法是安全的(避免无限重复),不是因为转换而是因为它用%f调用Sprintf,%f不是字符串格式,Sprintf只会在需要字符串时调用String方法 , %f 表示想要一个浮点值。

变量

变量可以像常量一样初始化,但初始化器可以是在运行时计算的通用表达式。

var (
    home   = os.Getenv("HOME")
    user   = os.Getenv("USER")
    gopath = os.Getenv("GOPATH")
)

初始化方法

最后,每个源文件都可以定义自己的 init 函数来设置所需的任何状态。 (实际上每个文件可以有多个 init 函数。) 请注意是这里表达的是「最后」的意思,在包中的所有变量声明都对它们的初始值进行设定后,最后会调用 init,另外,只有在所有导入的包都被初始化之后才会开始设定初始值。

init 函数的一个常见用途是在实际执行开始之前验证或修复程序状态的正确性。

func init() {
    if user == "" {
        log.Fatal("$USER not set")
    }
    if home == "" {
        home = "/home/" + user
    }
    if gopath == "" {
        gopath = home + "/go"
    }
    // gopath may be overridden by --gopath flag on command line.
    flag.StringVar(&gopath, "gopath", gopath, "override default GOPATH")
}

\