# Go basic syntax ### for ```go= sum := 0 for i := 0; i < n; i++ { sum += i } fmt.Println(sum) // 省略前後的 for sum := 1 for ; i < n; { sum += sum } fmt.Println(sum) ``` ### while go 沒有 `while` !!! ```go= // 沒有分號的 for 就是 while! sum := 1 for sum < 1000 { sum += sum } fmt.Println(sum) ``` ### array ```go= var arr [5]int fmt.Println(len(arr)) // 5 // initial x := [4]float64{23, 45, 33, 21} // more simple x := [4]float64{ 23, 45, 33, 21, } ``` ### range 會回傳 key, value 沒用到的 key 要用 `_` 接住,否則有變數沒用到會編譯錯誤( ```go= for _, value := range x { total += value } ``` ### slice 可變動長度陣列 array 的 [] 不要放數字,就是 slice ㄌ ```go= // 宣告 var x []float64 // 宣告且設定長度、容量,len = 5, capacity = 5 x := make([]float64, 5) // 宣告且設定長度、容量,len = 5, capacity = 10(多打一個數字就是 slice 的容量) x := make([]float64, 5, 10) arr := [5]float64{1,2,3,4,5} x := arr[0:5] // {1,2,3,4,5} x := arr[1:4]// {2,3,4} x := arr[:] // {1,2,3,4,5} ``` ### append ```go= slice1 := []int{1,2,3} slice2 := append(slice1, 4, 5) // {1, 2, 3, 4, 5} // 以下非宣告,不可用 := slice2 = append(slice2, 6, 7) // {1, 2, 3, 4, 5, 6, 7} ``` ### copy ```go= slice1 := []int{1,2,3} // 宣告 slice2 := make([]int, 2) // 宣告且設定長度、容量,len = capacity = 2 copy(slice2, slice1) // 因容量為 2,slice2 實際上只有 {1, 2} ``` ### map ```go= x := make(map[string]int) x["key"] = 10 fmt.Println(x["key"]) // delete delete(x, 1) // len len(x) // 判斷有沒有這個 key name, ok := elements["Al"] fmt.Println(name, ok) // 更漂亮個寫法 if name, ok := elements["Al"]; ok { fmt.Println(name, ok) } // 宣告初始值 elements := map[string]string{ "H": "Hydrogen", "He": "Helium", "Li": "Lithium", "Be": "Beryllium", "B": "Boron", "C": "Carbon", "N": "Nitrogen", "O": "Oxygen", "F": "Fluorine", "Ne": "Neon", } // 也可以是巢狀 map ``` ### function 很符合 go 的宣告方式 ```go= func add(x int, y int) int { return x + y } // 都是 int, 也可以寫成 func add(x int, y int) int { return x + y } // return 多值 func swap(x, y string) (string, string) { return y, x } // 把要回傳的值事先命名在函式中,就可以只打 return func split(sum int) (x, y int) { x = sum * 4 / 9 y = sum - x return } ``` ### Goroutines 開心的 thread 平行處理 ```go= func f(n int) { for i := 0; i < 10; i++ { fmt.Println(n, ":", i) } } func main() { go f(0) // time.Sleep(time.Second \* 1) // 暫停一秒鐘,讓 f(0) 有時間印出來 } ``` ### Channel ```go= package main import "fmt" func main() { // 建立 channel messages := make(chan string) go func() { messages <- "ping" }() // 把 "ping" 傳到 messages msg := <-messages // 再用 msg 接住 messages (在另一個 goroutine 裡做的) fmt.Println(msg) } ``` ### select select for channel ```go= func main() { c1 := make(chan string) // channel string c2 := make(chan string) go func() { // Goroutine1, to channel 1 time.Sleep(time.Second * 1) c1 <- "one" }() go func() { // Goroutine2, to channel 2 time.Sleep(time.Second * 2) c2 <- "two" }() for i := 0; i < 2; i++ { select { case msg1 := <-c1: // 當 c1 傳回 msg1 fmt.Println("received", msg1) // one case msg2 := <-c2: // 當 c2 傳回 msg2 fmt.Println("received", msg2) // two } } } ``` ### defer 離開函式前要做的事 目的:原本每個 return 前都要寫,現在只要寫在函式一開始,不管從哪的 return 都會執行 ```go= func demo() error { f, err := os.Create("/tmp/loglog") if err != nil { return err } defer f.Close() // do something } ``` ```go= func demo() { n := 0 defer fmt.Println(n) n ++ defer fmt.Println(n) } // result = 1 0(當下 n 作為參數傳入)(後宣告的 defer 會先做) ``` ```go= func demo() { n := 0 defer func() { fmt.Println(n) }() n++ defer func() { fmt.Println(n) }() } // result = 1 1(call function 輸出 n 的值,不是當用當下 n 值當作參數傳入) ``` ### 可變參數個數函式 ```go= package main import "fmt" func sum(nums ...int) { fmt.Print(nums, " ") total := 0 for _, num := range nums { total += num } fmt.Println(total) } func main() { sum(1, 2) sum(1, 2, 3) nums := []int{1, 2, 3, 4} sum(nums...) } ``` - func name(slice ...int) - 可以直接丟數字,也可以包成 slice,再用 fun(slice...) 的樣子呼叫