# Day05 開寫程式Go,變數宣告前方小坑
---
## 開寫程式"蛤螺握德"
新增一個helloWorld資料夾,裡面創建main.go檔案。
```go
package main
import "fmt"
func main() {
fmt.Println("Hello World!!")
}
```
~~ㄝ? 圖中ㄉ資料夾不符 請無視~~

## 執行
寫完存檔後,到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