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