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 between initialized objects in different packages are handled correctly. express
从表面上看 Go的初始化和C/C++区别不大 可是Go更加给力 复杂的数据结构能够在初始化的时候创建起来 而且Go能够准确地处理不一样包之间的对象初始化顺序 安全
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, 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)就不是常量表达式 由于这里涉及到了函数调用 这个是在运行时才进行计算的 app
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. ide
Go中的枚举常量 能够经过iota来建立 因为iota能够是表达式的一部分 并且表达式能够被重复 能够很容易地建立复杂的数据集 每个const关键字出现时 iota会被重置为0 iota会在下一次引用时自动+1 当const赋值表达式相同时可省略以后的赋值表达式 下面的这个例子的赋值表达式就省略了 统一为 1<<(10*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
)
The ability to attach a method such as String to a type makes it possible for such values to format themselves automatically for printing, even as part of a general type. ui
Go中能够为大多数类型定义方法 好比为某个类型定义String方法 就能够输出改类型的字符串表达形式 lua
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. spa
经过这个函数 YB能够打印成1.00YB, 而ByteSize(1e13)则打印成9.09TB rest
Note that it's fine to call Sprintf and friends in the implementation of String methods, but beware of recurring into the String method through the nested Sprintf call using a string format (%s, %q, %v, %x or %X). The ByteSize implementation of String is safe because it calls Sprintf with %f.
在写String函数的时候 能够调用Sprintf以及相关的输出函数 可是要注意防止Sprintf使用格式化修饰符%s, %q, %v, %x, %X, 这里ByteSize的String方法是安全的 由于只用了%f修饰符
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") goRoot = os.Getenv("GOROOT") )
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.
每一个源文件均可以定义本身的init初始化函数(能够有多个init函数)init会在全部包中 变量初始化完成后调用 这个概念能够和其它面向对象的构造函数作对比 最特征化的子类 最后才被初始化 而父类最早被初始化
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.
init的一般用在 程序真正执行前 验证而且修复程序的状态
func init() { if user == "" { log.Fatal("$USER not set") } if home == "" { home = "/home/" + user } if goRoot == "" { goRoot = home + "/go" } // goRoot may be overridden by --goroot flag on command line. flag.StringVar(&goRoot, "goroot", goRoot, "Go root directory") }