5.9. 初始化
尽管表面看来和 C 或 C++ 的初始化没什么不同,Go 的更够强。复杂结构可在初始化时架设,并且不同包的物件的初始化顺序问题也得到正确处理。
5.9.1. Constants 常量初始化
常量在 Go 里是 —— 不变的。它们在编译时生成,即便是局部定义在函数里。它只能是数,字串或布尔。因为编译态的限制,定义它们的表达式必须是常量表达式,可以被编译器求值。例如,1<<3 是常量表达式, math.Sin(math.Pi/4) 不是,因为 math.Sin 的函数调用发生在运行态。
Go 的列举常量可用 iota 生成。 因为 iota 可以是表达式的一部分,并且表达式可以隐含重复,打造一套精致的值可以变得很容易。
type ByteSize float64
const (
_ = iota // ignore first value by assigning to blank identifier
KB ByteSize = 1<<(10*iota)
MB
GB
TB
PB
EB
ZB
YB
)
给类型添加比如 String 等方法的本领,使值自动排版打印自己变得可能,即使只作为通用类型的一部分。
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
5.9.2. 变量初始化
变量和常量的初始化一样,但可以用运行态计算的普通表达式。
var (
HOME = os.Getenv("HOME")
USER = os.Getenv("USER")
GOROOT = os.Getenv("GOROOT")
)
5.9.3. init函数
最后,每个源文件可以定义自身的 init() 函数来安排所需的状态。唯一的限制是,尽管够程可在初始化时启动,它们只在初始完成后执行;初始化永远是单一的执行序列。最后之后,init() 发生在包里所有变量初始化之后,而其又发生在所有的包全部导入之后。
除了初始化不能表示为声明外,init() 函数常用来在程序运行前验证或修补其状态。
func init() {
if USER == "" {
log.Exit("$USER not set")
}
if HOME == "" {
HOME = "/usr/" + USER
}
if GOROOT == "" {
GOROOT = HOME + "/go"
}
// GOROOT may be overridden by --goroot flag on command line.
flag.StringVar(&GOROOT, "goroot", GOROOT, "Go root directory")
}