---
# System prepended metadata

title: 來學點 Go !!
tags: [Go]

---

# 來學點 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())
        }
        
        /**
         * 印出結果
         *   叫聲是 汪！
         *   叫聲是 喵！
         *   叫聲是 哞！
         */
    }

     
     ```
     
### 