# Day05 開寫程式Go,變數宣告前方小坑 --- ## 開寫程式"蛤螺握德" 新增一個helloWorld資料夾,裡面創建main.go檔案。 ```go package main import "fmt" func main() { fmt.Println("Hello World!!") } ``` ~~ㄝ? 圖中ㄉ資料夾不符 請無視~~ ![helloWorld](https://i.imgur.com/RNMqgrU.png) ## 執行 寫完存檔後,到helloWorld資料夾裡下 $ go run main.go > 這一行的效果等於以下兩行 > > `$ go build main.go` 編譯出一個執行檔 > `$ ./main.exe` 接著執行它 > > (但 `go run` 產生的執行檔是在電腦的暫存區/tmp下) 或者用Goland IDE,直接按預設快捷鍵 Ctrl + Shift + F10(for windows) Ctrl + Shift + R(for Mac) 編譯&執行 --- ## 【變數宣告】 **變數宣告了就要使用,** 否則會出現variable declared and not used的錯誤。 **除非變數的名稱為`_`** > **var Name Type = Expression** >> var a int = 16 > > 要嘛省略`型別 Type`,由`Expression`決定`Type` > 要嘛省略`表達式 Expression`,變數值為 `Type` 的`初始值(零值)` > 初始值(零值):0, false, "", nil 等等 https://play.golang.org/p/MnmDT24cMTQ ```go func main() { var a = 16 var b int var _ = 10 fmt.Println(a, b) } // result: // 16 0 ``` #### 短變數宣告(用:= 代替var) 短變數宣告(Short variable declarations) > **Name := Expression** >> a := 10 宣告`declare(:=)` 跟 指派`assign(=)`是不同的, 一次宣告多個變數,若已宣告過的變數會自動變成assign效果 #### 宣告多個變數 https://play.golang.org/p/cy6L6tKz01n ```go func main() { var b int = 123 a, b := 100, 99 c, b := 0, 1 fmt.Println(a, b, c) } // result: // 100 1 0 ``` > 短變數宣告 **(:=)** 方法簡便, > 常用在宣告初始化大量、生命週期短的區域變數(就是迴圈內的i, j啦); > 反之,**var** 則常用在明確設定型別、生命週期較長的變數。 ## 【前方坑洞注意】-宣告區域變數 **坑A範例** https://play.golang.org/p/1aI9NdAdrQ_T ```go package main import "fmt" var a = "Hello!" func main() { b := 10 fmt.Println(&a, a, &b, b) a, b := 100, 99 fmt.Println(&a, a, &b, b) } /* result: 0x54dc50 Hello! 0xc00002c008 10 0xc00002c048 100 0xc00002c008 99 */ ``` 發現了嗎? 只要有 `var`或`:=` 出現,就是宣告新的變數、挪用新的記憶體空間 所以導致全域變數`a`的地址被蓋掉了 ### 但當你正這麼想的同時,再來看看下面這個範例 **坑B範例** https://play.golang.org/p/3iAo5wIt32D ```go package main import "fmt" var i = 123 // 全域變數 func main() { fmt.Println(&i) i = 123 fmt.Println(&i) i := 123 // 全新的。func區塊內的區域變數 fmt.Println(&i) i, j := 123, 100 fmt.Println(&i, j) // 奇怪?i沒有變新的啊 } /* 運行結果 0x11662a0 0x11662a0 0xc0000b2008 0xc0000b2008 100 */ ``` 只要有 `var`或`:=` 出現,就會挪用全新的記憶體空間嗎? 答案是:不一定。 程式會去查找**目前最小單位的區塊內** 是否已經有宣告過的變數, 沒有的話才會宣告新的。 ### 這個變數到底是不是全新的? 看到有 `var` 會是全新的。 但看到 `:=` 卻是不一定,短變數宣告可以伴隨著未宣告的變數一起出現。 https://play.golang.org/p/E3xcRJjTTjx ```go package main import "fmt" var x = 123 // 全域變數 func main() { fmt.Println(&x) var x = 123 // 在`func區塊`。全新。 fmt.Println(&x) // var x, y = 123, 100 // 因為x已經宣告過了,不能再用`var`。但以下卻可以 x, y := 123, 100 // 在`func區塊`。此時x是上面宣告過的區域變數,而y是新的 fmt.Println(&x, &y) if true { var x, y = 123, 100 // 在新區域`if區塊`。此時x跟y都是全新的。 // 可以換成短變數宣告。 fmt.Println(&x, &y) } fmt.Println(&x) // 脫離if區域,回到`func區塊` } /* 運行結果 0x11662a0 0xc000016080 0xc000016080 0xc000016088 0xc000016090 0xc000016098 0xc000016080 */ ``` 未來會常常看到下面這種用法 connect, err := ...(server) 或者 result, err := ... 此時`:=`左邊的兩個變數,**都會是區域變數**, 不是你外面宣告的全域變數。 另外 * 宣告全域變數只能用`var`,無法用`:=` --- ## 常數宣告 常數:無法更動、無法刪除的變數 但用法跟變數`var`一樣,`const`後面可以接任何型別, 因為常數硬梆梆的,所以單字通常為**全大寫** ```go const PI = 3.14159 const HELLO = "Hello World" ``` #### 【iota】 `iota`是[希臘字符](https://zh.wiktionary.org/wiki/iota),在Golang中是關鍵字之一,用在宣告常數中, 效果為**數字遞增**,`iota`本身數值從0開始, 便於工程師不用手動打數字0、1、2、3...重複且無聊的事情。 ```go const ( A = iota // 0 B // 1 _ // 2 佔位符也會被計算 C // 3 D = iota * 0.1 // 0.4 接續前面的 iota E // 0.5 F // 0.6 G // 0.7 ) ``` 起始值也不一定要從0開始 ```go const ( X = iota + 100 // 100 Y // 101 Z // 102 ) ``` 也常被拿來作 **左移右移(Shift Bit)** 運算 ```go const ( b1 = 1 << iota // 1 右側被塞入0個bit (2^0 二的零次方) b2 // 2 右側被塞入1個bit (2^1 二的一次方) b3 // 4 右側被塞入2個bit b4 // 8 b5 // 16 ) ``` https://play.golang.org/p/jVOzeLxu-mB