# 來學點 Go !!
###### tags: `Go`
### 前情提要
* 資料參考
> [初學 Golang 30 天](https://ithelp.ithome.com.tw/articles/10155678)
> [Go by Exampl](https://gobyexample.com)
> [ZetCode: Go interface](https://zetcode.com/golang/interface/)
* 分點章節
> [來學點 Go !](/PHSJz1oER0S1Z4COWM0eyA)
> [來學點 Go !!](/V39Yd1B1RK-fUjAYEyJJLQ)
### 寫點什麼涵式 (func)
* 簡單的加減
```go
package main
import (
"fmt"
"math/rand"
)
func main() {
// 取亂數 n1, n2
n1 := rand_int()
n2 := rand_int()
// 亂數相加
sum := add(n1, n2)
fmt.Println(n1, `+`, n2, `=`, sum)
// 取得一個新亂數
rn := rand_int()
// 暫存計算前的和數 sum
rs := fmt.Sprintf(`%d - %d =`, sum, rn)
// 計算減 併 印出結果
sum = sub(sum, rn)
fmt.Println(rs, sum)
}
// 簡單的加
func add(n1 int, n2 int) int {
return n1 + n2
}
// 簡單的減
func sub(n1 int, n2 int) int {
return n1 - n2
}
// 簡單的亂數
func rand_int() int {
/**
* 直接用 rand.Intn 會發現都是取得固定的 81, 87, ....
* 所以需要用點不一定的方法
* 設置亂數種子 seed, 來源 timestamp
* ex: 1634622793227340319
* 然後用亂數種子為樣本取得新亂數
*/
seed := rand.NewSource(time.Now().UnixNano())
return rand.New(seed).Intn(100)
}
```
### 踩點什麼錯誤 (error)
* 簡單的加減有可能出現這樣的結果
```shell
$ go run main.go
0 + 4 = 4
4 - 31 = -27
```
* 那是不是該加點什麼避免出現負數呢!
```go
/**
* 加個檢查式
*
* 注意:
* 這邊回傳用了 多參數回傳
* 所以要記得 回傳型別也要跟著改變
*/
func is_positive_int(n int) (bool, error) {
if n < 0 {
return true, errors.New("必須是正整數!")
}
return false, nil
}
```
* 主程序加個判斷式
```go
func main() {
// 取亂數 n1, n2
n1 := rand_int()
n2 := rand_int()
// 亂數相加
sum := add(n1, n2)
fmt.Println(n1, `+`, n2, `=`, sum)
// 取得一個新亂數
rn := rand_int()
// 暫存計算前的和數 sum
rs := fmt.Sprintf(`%d - %d =`, sum, rn)
// 計算減 併 印出結果
sum = sub(sum, rn)
// 判斷計算結果
if _, err := is_positive_int(sum); err != nil {
fmt.Println(err)
// 發生錯誤,終止程序
os.Exit(1)
}
// 印出結果
fmt.Println(rs, sum)
}
```
### 自定點什麼結構 (struct)
* 使用者嘛,總是會有那幾樣...
```go
type user struct {
// 名字啦
name string
// 手機啦
phone string
// 年齡啦
age int
// 什麼啦
subscription bool
}
func main() {
fmt.Println(user{"使用者1號", "09蝦咪啦", 26, false})
// {使用者1號 09蝦咪啦 26 false}
fmt.Println(user{"使用者2號", "", 32, true})
// {使用者2號 32 true}
fmt.Println(user{"使用者3號", "", 0, false})
// {使用者3號 0 false}
}
```
### 追加點什麼方法 (method)
* 年紀到了總會被說...老了
```go
type people struct {
name string
age int
}
func main() {
// 建立一個 people 的陣列
peoples := []people{
people{"1號", 72},
people{"2號", 63},
people{"3號", 54},
people{"4號", 45},
people{"5號", 36},
}
// 透過 range 跑陣列迴圈
for k, v := range peoples {
fmt.Printf("[%v] %v\n", k, v.age_stage())
}
/**
* 印出結果
* [0] 1號正處於 七十古來稀
* [1] 2號正處於 六十耳順
* [2] 3號正處於 五十知天命
* [3] 4號正處於 四十不惑
* [4] 5號正處於 三十而立
*/
}
// 對結構 people 追加一個年齡階段 age_stage 的方法
func (p people) age_stage() string {
r := p.name + "正處於"
switch {
case p.age >= 70:
r += " 七十古來稀"
case p.age >= 60:
r += " 六十耳順"
case p.age >= 50:
r += " 五十知天命"
case p.age >= 40:
r += " 四十不惑"
case p.age >= 30:
r += " 三十而立"
case p.age < 30:
r += " 屁孩一個"
}
return r
}
```
### 實作點什麼介面 (interface)
* 多數的動物都會叫!
```go
// 宣告一個動物 anime的介面
type anime interface {
sound() string
}
// 宣告狗的結構
type dog struct {}
// 對狗追加 sound 的方法
func (anime dog) sound() string { return "汪!" }
// 宣告貓的結構
type cat struct {}
// 對貓追加 sound 的方法
func (anime cat) sound() string { return "喵!" }
// 宣告牛的結構
type cow struct {}
// 對牛追加 sound 的方法
func (anime cow) sound() string { return "哞!" }
// 煮程序
func main() {
// 宣告動物們的變數, 且初始賦予 狗, 貓, 牛
animes := []anime{dog{}, cat{}, cow{}}
// 用迴圈跑資料, 這邊因為不會用到 key 所以用了 _ 來代表接收回應但不使用
for _, val := range animes {
fmt.Println("叫聲是", val.sound())
}
/**
* 印出結果
* 叫聲是 汪!
* 叫聲是 喵!
* 叫聲是 哞!
*/
}
```
###