golang學習筆記 ---命名
Go語言中的函式名、變數名、常量名、型別名、語句標號和包名等所有的命名,都遵循一個
簡單的命名規則:一個名字必須以一個字母(Unicode字母)或下劃線開頭,後面可以跟任意
數量的字母、數字或下劃線。大寫字母和小寫字母是不同的:heapSort和Heapsort是兩個不
同的名字。
Go語言中類似if和switch的關鍵字有25個;關鍵字不能用於自定義名字,只能在特定語法結構
中使用。
break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var
此外,還有大約30多個預定義的名字,比如int和true等,主要對應內建的常量、型別和函式。
內建常量: true false iota nil 內建型別: int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr float32 float64 complex128 complex64 bool byte rune string error 內建函式: make len cap new append copy close delete complex real imag panic recover
這些內部預先定義的名字並不是關鍵字,你可以再定義中重新使用它們。在一些特殊的場景
中重新定義它們也是有意義的,但是也要注意避免過度而引起語義混亂。
如果一個名字是在函式內部定義,那麼它的就只在函式內部有效。如果是在函式外部定義,
那麼將在當前包的所有檔案中都可以訪問。名字的開頭字母的大小寫決定了名字在包外的可
見性。如果一個名字是大寫字母開頭的(譯註:必須是在函式外部定義的包級名字;包級函
數名本身也是包級名字),那麼它將是匯出的,也就是說可以被外部的包訪問,例如fmt包的
Printf函式就是匯出的,可以在fmt包外部訪問。包本身的名字一般總是用小寫字母。
宣告
Go語言主要有四種類型的宣告
語句:var、const、type和func,分別對應變數、常量、型別和函式實體物件的宣告
package main import "fmt" const boilingF = 212.0 func main() { var f = boilingF var c = (f - 32) * 5 / 9 fmt.Printf("boiling point = %g°F or %g°C\n", f, c) // Output: // boiling point = 212°F or 100°C }
其中常量boilingF是在包一級範圍宣告語句宣告的,然後f和c兩個變數是在main函式內部宣告
的宣告語句宣告的。在包一級宣告語句宣告的名字可在整個包對應的每個原始檔中訪問,而
不是僅僅在其宣告語句所在的原始檔中訪問。相比之下,區域性宣告的名字就只能在函式內部
很小的範圍被訪問。
package main import "fmt" func main() { const freezingF, boilingF = 32.0, 212.0 fmt.Printf("%g°F = %g°C\n", freezingF, fToC(freezingF)) // "32°F = 0°C" fmt.Printf("%g°F = %g°C\n", boilingF, fToC(boilingF)) // "212°F = 100°C" } func fToC(f float64) float64 { return (f - 32) * 5 / 9 }
一個函式的宣告由一個函式名字、引數列表(由函式的呼叫者提供引數變數的具體值)、一
個可選的返回值列表和包含函式定義的函式體組成。如果函式沒有返回值,那麼返回值列表
是省略的。執行函式從函式的第一個語句開始,依次順序執行直到遇到renturn返回語句,如
果沒有返回語句則是執行到函式末尾,然後返回到函式呼叫者。
變數
var宣告語句可以建立一個特定型別的變數,然後給變數附加一個名字,並且設定變數的初始
值。變數宣告的一般語法如下:
var 變數名字 型別 = 表示式
其中“型別”或“= 表示式”兩個部分可以省略其中的一個。如果省略的是型別資訊,那麼將根據
初始化表示式來推導變數的型別資訊。如果初始化表示式被省略,那麼將用零值初始化該變
量。 數值型別變數對應的零值是0,布林型別變數對應的零值是false,字串型別對應的零
值是空字串,介面或引用型別(包括slice、map、chan和函式)變數對應的零值是nil。數
組或結構體等聚合型別對應的零值是每個元素或欄位都是對應該型別的零值。
零值初始化機制可以確保每個宣告的變數總是有一個良好定義的值,因此在Go語言中不存在
未初始化的變數。這個特性可以簡化很多程式碼,而且可以在沒有增加額外工作的前提下確保
邊界條件下的合理行為。
Go語言程式設計師應該
讓一些聚合型別的零值也具有意義,這樣可以保證不管任何型別的變數總是有一個合理有效
的零值狀態。
可以在一個宣告語句中同時宣告一組變數,或用一組初始化表示式宣告並初始化一組變
量。如果省略每個變數的型別,將可以宣告多個型別不同的變數(型別由初始化表示式推
導):
var i, j, k int // int, int, int var b, f, s = true, 2.3, "four" // bool, float64, string
初始化表示式可以是字面量或任意的表示式。在包級別宣告的變數會在main入口函式執行前
完成初始化(§2.6.2),區域性變數將在宣告語句被執行到的時候完成初始化。
一組變數也可以通過呼叫一個函式,由函式返回的多個返回值初始化:
var f, err = os.Open(name)
簡短變數宣告
在函式內部,有一種稱為簡短變數宣告語句的形式可用於宣告和初始化區域性變數。它以“名字
:= 表示式”形式宣告變數,變數的型別根據表示式來自動推導。
anim := gif.GIF{LoopCount: nframes} freq := rand.Float64() * 3.0 t := 0.0
i, j := 0, 1
f, err := os.Open(name) if err != nil { return err } // ...use f... f.Close()
請記住“:=”是一個變數宣告語句,而“=‘是一個變數賦值操作
在下面的程式碼中,第一個語句聲明瞭in和err兩個變數。在第二個語句只聲明瞭out一個變數,
然後對已經宣告的err進行了賦值操作。
in, err := os.Open(infile) // ... out, err := os.Create(outfile)
簡短變數宣告語句中必須至少要宣告一個新的變數,下面的程式碼將不能編譯通過:
f, err := os.Open(infile) // ... f, err := os.Create(outfile) // compile error: no new variables
解決的方法是第二個簡短變數宣告語句改用普通的多重賦值語言。
var形式的宣告語句往往是用於需要顯式指定變數型別地方,或者因為變數稍後會被重新賦值而初始值無關緊要的地方。
i := 100 // an int var boiling float64 = 100 // a float64 var names []string var err error var p Point
任何型別的指標的零值都是nil。如果 p != nil 測試為真,那麼p是指向某個有效變數。指標
之間也是可以進行相等測試的,只有當它們指向同一個變數或全部是nil時才相等。
var x, y int fmt.Println(&x == &x, &x == &y, &x == nil) // "true false false"
在Go語言中,返回函式中區域性變數的地址也是安全的。例如下面的程式碼,呼叫f函式時建立局
部變數v,在區域性變數地址被返回之後依然有效,因為指標p依然引用這個變數。
var p = f() func f() *int { v := 1 return &v }
每次呼叫f函式都將返回不同的結果:
fmt.Println(f() == f()) // "false"