---
# System prepended metadata

title: Go basic syntax

---

# 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...) 的樣子呼叫
