這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
Initialization
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.
從表面上看 Go的初始化和C/C++區別不大 但是Go更加給力 複雜的資料結構可以在初始化的時候建立起來 並且Go可以準確地處理不同包之間的對象初始化順序
Constants 常量初始化
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)就不是常量運算式 因為這裡涉及到了函數調用 這個是在運行時才進行計算的
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.
Go中的枚舉常量 可以通過iota來建立 由於iota可以是運算式的一部分 而且運算式可以被重複 可以很容易地建立複雜的資料集 每一個const關鍵字出現時 iota會被重設為0 iota會在下一次引用時自動+1 當const賦值運算式相同時可省略之後的賦值運算式 下面的這個例子的賦值運算式就省略了 統一為 1<<(10*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)
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.
Go中可以為大多數類型定義方法 比如為某個類型定義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)}
The expression YB prints as 1.00YB, while ByteSize(1e13) prints as 9.09TB.
通過這個函數 YB可以列印成1.00YB, 而ByteSize(1e13)則列印成9.09TB
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 變數初始化
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"))
The init function 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.
每個源檔案都可以定義自己的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")}