## 初始化

Although it doesn’t look superficially very different from initialization in C or C++, initialization in Go is more powerful. Complex structures can be built during initialization and the ordering issues among initialized objects, even among different packages, are handled correctly.

### 常量

Constants in Go are just that—constant. They are created at compile time, even when defined as locals in functions, and can only be numbers, characters (runes), strings or booleans. Because of the compile-time restriction, the expressions that define them must be constant expressions, evaluatable by the compiler. For instance, 1<<3 is a constant expression, while math.Sin(math.Pi/4) is not because the function call to math.Sin needs to happen at run time.

Go 中的常量就是不变量。它们在编译时创建，即便它们可能是函数中定义的局部变量。 常量只能是数字、字符（符文）、字符串或布尔值。由于编译时的限制， 定义它们的表达式必须也是可被编译器求值的常量表达式。例如 1<<3 就是一个常量表达式，而 math.Sin(math.Pi/4) 则不是，因为对 math.Sin 的函数调用在运行时才会发生。

In Go, enumerated constants are created using the iota enumerator. Since iota can be part of an expression and expressions can be implicitly repeated, it is easy to build intricate sets of values.

type ByteSize float64const (    // 通过赋予空白标识符来忽略第一个值    _           = iota // ignore first value by assigning to blank identifier    KB ByteSize = 1 << (10 * iota)    MB    GB    TB    PB    EB    ZB    YB)

The ability to attach a method such as String to any user-defined type makes it possible for arbitrary values to format themselves automatically for printing. Although you’ll see it most often applied to structs, this technique is also useful for scalar types such as floating-point types like 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)}

The expression YB prints as 1.00YB, while ByteSize(1e13) prints as 9.09TB.

The use here of Sprintf to implement ByteSize’s String method is safe (avoids recurring indefinitely) not because of a conversion but because it calls Sprintf with %f, which is not a string format: Sprintf will only call the String method when it wants a string, and %f wants a floating-point value.

### 变量

Variables can be initialized just like constants but the initializer can be a general expression computed at run time.

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

### init 函数

Finally, each source file can define its own niladic init function to set up whatever state is required. (Actually each file can have multiple init functions.) And finally means finally: init is called after all the variable declarations in the package have evaluated their initializers, and those are evaluated only after all the imported packages have been initialized.

Besides initializations that cannot be expressed as declarations, a common use of init functions is to verify or repair correctness of the program state before real execution begins.

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")} func init() { if user == "" { log.Fatal("$USER not set")    }    if home == "" {        home = "/home/" + user    }    if gopath == "" {        gopath = home + "/go"    }    // gopath 可通过命令行中的 --gopath 标记覆盖掉。    flag.StringVar(&gopath, "gopath", gopath, "override default GOPATH")}