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") }