golang學習筆記3:常量與變數
常量
常量使用關鍵字 const 定義,用於儲存不會改變的資料。
儲存在常量中的資料型別只可以是布林型、數字型(整數型、浮點型和複數)和字串型。
常量的定義格式: const identifier [type] = value ,例如:
1. const Pi = 3.14159
在 Go 語言中,你可以省略型別說明符 [type] ,因為編譯器可以根據變數的值來推斷其型別。
顯式型別定義: const b string = "abc"
隱式型別定義: const b = "abc"
一個沒有指定型別的常量被使用時,會根據其使用環境而推斷出它所需要具備的型別。換句話說,未定義型別的常量
會在必要時刻根據上下文來獲得相關型別。
1. var n int2. f(n + 5) // 無型別的數字型常量 “5” 它的型別在這裡變成了 int
常量的值必須是能夠在編譯時就能夠確定的;你可以在其賦值表示式中涉及計算過程,但是所有用於計算的值必須在
編譯期間就能獲得。
正確的做法: const c1 = 2/3
錯誤的做法: const c2 = getNumber() // 引發構建錯誤: getNumber() used as value
因為在編譯期間自定義函式均屬於未知,因此無法用於常量的賦值,但內建函式可以使用,如:len()。
數字型的常量是沒有大小和符號的,並且可以使用任何精度而不會導致溢位:
1. const Ln2= 0.693147180559945309417232121458\2. 1765680755001343602552541206800093. const Log2E= 1/Ln2 // this is a precise reciprocal4. const Billion = 1e9 // float constant5. const hardEight = (1 << 100) >> 97
根據上面的例子我們可以看到,反斜槓 \ 可以在常量表達式中作為多行的連線符使用。與各種型別的數字型變數相比,你無需擔心常量之間的型別轉換問題,因為它們都是非常理想的數字。
不過需要注意的是,當常量賦值給一個精度過小的數字型變數時,可能會因為無法正確表達常量所代表的數值而導致溢位,這會在編譯期間就引發錯誤。另外,常量也允許使用並行賦值的形式:
1. const beef, two, c = "eat", 2, "veg"2. const Monday, Tuesday, Wednesday, Thursday, Friday, Saturday = 1, 2, 3, 4, 5, 63. const (4. Monday, Tuesday, Wednesday = 1, 2, 35. Thursday, Friday, Saturday = 4, 5, 66. )
常量還可以用作列舉:
1. const (2. Unknown = 03. Female = 14. Male = 25. )
現在,數字 0、1 和 2 分別代表未知性別、女性和男性。這些列舉值可以用於測試某個變數或常量的實際值,比如使用 switch/case 結構.
變數
宣告變數的一般形式是使用 var 關鍵字: var identifier type 。需要注意的是,Go 和許多程式語言不同,它在宣告變數時將變數的型別放在變數的名稱之後。Go 為什麼要選擇這麼做呢?首先,它是為了避免像 C 語言中那樣含糊不清的宣告形式,例如: int* a, b; 。在這個例子中,只有 a 是指標而b 不是。如果你想要這兩個變數都是指標,則需要將它們分開書寫.而在 Go 中,則可以很輕鬆地將它們都宣告為指標型別:
1. var a, b *int
其次,這種語法能夠按照從左至右的順序閱讀,使得程式碼更加容易理解。
示例:
1. var a int2. var b bool3. var str string
你也可以改寫成這種形式:
1. var (2. a int3. b bool4. str string5. )
這種因式分解關鍵字的寫法一般用於宣告全域性變數。
當一個變數被宣告之後,系統自動賦予它該型別的零值:int 為 0,float 為 0.0,bool 為 false,string為空字串,指標為 nil。記住,所有的記憶體在 Go 中都是經過初始化的。
變數的命名規則遵循駱駝命名法,即首個單詞小寫,每個新單詞的首字母大寫,例如: numShips 和 startDate 。
但如果你的全域性變數希望能夠被外部包所使用,則需要將首個單詞的首字母也大寫。
一個變數(常量、型別或函式)在程式中都有一定的作用範圍,稱之為作用域。如果一個變數在函式體外宣告,則被認為是全域性變數,可以在整個包甚至外部包(被匯出後)使用,不管你宣告在哪個原始檔裡或在哪個原始檔裡呼叫該變數。在函式體內宣告的變數稱之為區域性變數,它們的作用域只在函式體內,引數和返回值變數也是區域性變數。
我們將會學習到像 if 和 for 這些控制結構,而在這些結構中宣告的變數的作用域只在相應的程式碼塊內。一般情況下,區域性變數的作用域可以通過程式碼塊(用大括號括起來的部分)判斷。
儘管變數的識別符號必須是唯一的,但你可以在某個程式碼塊的內層程式碼塊中使用相同名稱的變數,則此時外部的同名變數將會暫時隱藏(結束內部程式碼塊的執行後隱藏的外部同名變數又會出現,而內部同名變數則被釋放),你任何的操作都只會影響內部程式碼塊的區域性變數。變數可以編譯期間就被賦值,賦值給變數使用運算子等號 = ,當然你也可以在執行時對變數進行賦值操作。
示例:
1. a = 152. b = false
一般情況下,當變數a和變數b之間型別相同時,才能進行如 a = b 的賦值。宣告與賦值(初始化)語句也可以組合起來。示例:
1. var identifier [type] = value2. var a int = 153. var i = 54. var b bool = false5. var str string = "Go says hello to the world!"
但是 Go 編譯器的智商已經高到可以根據變數的值來自動推斷其型別,這有點像 Ruby 和 Python 這類動態語言,只不過它們是在執行時進行推斷,而 Go 是在編譯時就已經完成推斷過程。因此,你還可以使用下面的這些形式來宣告及初始化變數:
1. var a = 152. var b = false3. var str = "Go says hello to the world!"
或:
1. var (2. a = 153. b = false4. str = "Go says hello to the world!"5. numShips = 506. city string7. )
不過自動推斷型別並不是任何時候都適用的,當你想要給變數的型別並不是自動推斷出的某種型別時,你還是需要顯式指定變數的型別,例如:
1. var n int64 = 2
然而, var a 這種語法是不正確的,因為編譯器沒有任何可以用於自動推斷型別的依據。變數的型別也可以在執行時實現自動推斷,例如:
1. var (2. HOME = os.Getenv("HOME")3. USER = os.Getenv("USER")4. GOROOT = os.Getenv("GOROOT")5. )
這種寫法主要用於宣告包級別的全域性變數,當你在函式體內宣告區域性變數時,應使用簡短宣告語法 := ,例如:
1. a := 1
下面這個例子展示瞭如何通過 runtime 包在執行時獲取所在的作業系統型別,以及如何通過 os 包中的函式 os.Getenv() 來獲取環境變數中的值,並儲存到 string 型別的區域性變數 path 中。
1. package main2.3. import (4. "fmt"5. "runtime"6. "os"7. )8.9. func main() {10. var goos string = runtime.GOOS11. fmt.Printf("The operating system is: %s\n", goos)12. path := os.Getenv("PATH")13. fmt.Printf("Path is %s\n", path)14. }
如果你在 Windows 下執行這段程式碼,則會輸出 The operating system is: windows 以及相應的環境變數的值;如果你在 Linux 下執行這段程式碼,則會輸出 The operating system is: linux 以及相應的的環境變數的值。
