# Day07 Go飆車囉-狂教基本語法(if, switch, for, log)
今天東西稍微多了點,
但忍耐一下,文章就快結束了。
各程式語言基本上大同小異
如果各位學過其他程式語言、已有程式底子,
那麼學`Golang`只剩下**適應Go的語法**。
>
> 但是學習嘛,想是一回事、做是一回事
> 看完文章別看過就好,還是要自己動手從零開始的打異世界程式
>
> 俗話說的好:學程式別無他法,唯有自己寫,才是自己的。
>
> 法二:找個工具人
## 語法斷句
在Go中,語法斷句需要分號`;` **但是你不用寫**(硬要寫也是可以啦)。
因為它會幫你產生,可以省鍵盤軸心壽命,夠佛。
> Like C, Go's formal grammar uses semicolons to terminate statements,
> but unlike in C, those semicolons do not appear in the source.
```go
a := 10;
b := 20;;
fmt.Println(a, b);;;;;
```
## 條件判斷
#### 【if 條件】
條件直接寫,不用加小括號
(要加也是可以啦,不會報錯,佛心公司)
```go
if Condition {
...
} else {
...
}
```
https://play.golang.org/p/DW0nTIuHWnk
#### 【Switch】
一次做多個`if`的判斷
可以把**條件代入`case`中,也可以放在`switch`上,**
一魚可以兩吃,佛心公司。
`case`跟`case`之間**不用`break`**,更加直觀,佛!
https://play.golang.org/p/hRVHoeW6_h9
```go
var i int = 2
switch i {
case 1:
fmt.Println("i is 1")
case 2:
fmt.Println("i is 2")
case 3:
fmt.Println("i is 3")
default:
fmt.Println("i is not 1, 2, 3")
}
//--------
var j int = 10
switch {
case j == 1:
fmt.Println("j is 1")
case j == 2:
fmt.Println("j is 2")
case j == 3:
fmt.Println("j is 3")
default:
fmt.Println("j is not 1, 2, 3")
}
```
## 迴圈
#### 【for迴圈】
`for loop` 完全不用小括號,省時省力,佛!
> **for Expression; Condition; Operation {
> ...
> }**
https://play.golang.org/p/o4EZytZSgt-
```go
for i:=0; i<10; i++{
fmt.Println(i)
}
```
#### 【while迴圈】
`Go` 沒有`While`關鍵字啦!記者標題!
但可以這樣用
> **for Condifion{
> ...
> }**
https://play.golang.org/p/xVLC_SsygHt
```go
i := 0
for i < 10{
fmt.Println(i)
i++
}
```
#### 【for迭代】
能夠遍歷整個物件變數,
另外用`for`迭代的話,就不能在裡頭**修改(新增、刪除)迭代物件**,會容易出問題
若真要修改物件,請用上面**for迴圈**的方式
> **for a, b := range Iterable{
> ...
> }**
https://play.golang.org/p/2N6FrtbpB6f
```go
nums := []int{100, 99, 98}
for index, num := range nums {
fmt.Println(index, num)
}
for index := range nums {
fmt.Println(index)
}
//--------
fruits := map[string]string{"a": "apple", "b": "banana"}
for index, fruit := range fruits {
fmt.Println(index, fruit)
}
for index := range fruits {
fmt.Println(index)
}
```
單單一個`for`關鍵字有這麼多用途,佛!
## Log日誌
#### 【log.Print】
#### 【log.Println】
#### 【log.Printf】
Go的`log.Print`用法跟`fmt.Print`用法基本上一致
但`log`會在開一個線程出來,而`fmt`則是運行在主線程上
```go
func main() {
for i:= 0; i <= 3; i++{
log.Println(i)
fmt.Println(i)
// time.Sleep(time.Millisecond * 10)
log.Println("hi")
fmt.Println("hi")
}
}
```
> 開線程這點在Windows的環境上看的出來(左);但在Playground及MacOS中運行起來是這樣(右)
> 
#### 【log.SetFlag】
改變印出的時間格式
```go
log.SetFlags(0)
log.SetFlags(1) 2020/09/13
log.SetFlags(2) 20:57:00
log.SetFlags(3) 2020/09/13 20:57:00
log.SetFlags(4) 20:57:00.862816
log.SetFlags(5) 2020/09/13 20:57:00.862816
```
也可以用常數名稱直接帶入`log.SetFlags(log.Ldate)`
關於SetFlags的參數
```go
const (
Ldate = 1 << iota // local time zone: 2009/01/23
Ltime //2 // local time zone: 01:23:23
Lmicroseconds //4 // microsecond : 01:23:23.123123.
Llongfile //8 // full filename, line: /a/b/c/d.go:23
Lshortfile //16 // filename element, line: d.go:23
LUTC //32 // use UTC
Lmsgprefix //64 // move the "prefix" from the beginning of the line to before the message
LstdFlags = Ldate | Ltime //3 預設Flag // initial standard logger
)
```
若想要同時印出 檔案名稱 `Lshortfile (16)` 及 日期 `Ldate(1)`,
則可直接相加數字,設定為`log.SetFlags(17)`,以此類推。
也可以用`|` **(或運算or)** `log.SetFlags(log.Lmsgprefix | log.LstdFlags)`
格式可以自己兜,任君挑選,**佛!**
https://play.golang.org/p/IIoJo55I8sr
```go
import (
"log"
)
func main() {
for i := 0; i <= 127; i++ {
log.SetFlags(i)
log.Print("log.SetFlags(", i, ")")
}
}
```
#### 【log.SetPrefix】
```go
log.SetPrefix("文字")
```
https://play.golang.org/p/gwCz6XNkjDx
``` go
func main() {
log.SetPrefix("安安,我是log ")
log.Println("Hi")
log.Fatalln("發生錯誤")
}
/* result:
安安,我是log 2009/11/10 23:00:00 Hi
安安,我是log 2009/11/10 23:00:00 發生錯誤
*/
```
#### 【log.Fatal】
#### 【log.Fatalf】
#### 【log.Fatalln】
用於發生錯誤時印出log並退出
點進去看go原始碼,退出的實作是多了`os.Exit(1)`這行
```go
func Fatal(v ...interface{}) {
std.Output(2, fmt.Sprint(v...))
os.Exit(1)
}
```
要自製logger,[可以參考此處](https://golang.org/pkg/log/#Logger)