iT邦幫忙

2025 iThome 鐵人賽

DAY 6
0
Modern Web

後端攻略筆記系列 第 6

Day 6 : Go語言 slice 與 map 應用練習 - 補充

  • 分享至 

  • xImage
  •  

回顧 Day 2 我們做的 Gross Store 練習 今天發生突發事件!!!!

📘 小劇場番外篇:錯誤處理特輯

Gross 雜貨舖最近生意太好,顧客一多,問題也跟著來啦!
今天小老闆要帶大家看看:如果顧客喊錯單位、退太多東西、或是查詢根本不存在的商品,**要怎麼用程式「防呆」和「錯誤處理」呢? **


錯誤題 1:客人喊了不存在的單位

顧客說:「老闆,給我一個 mega_gross 的柳丁!」
但我們的 Units 根本沒有 mega_gross

👉 請你修改 AddItem,讓它能回傳 error,避免錯誤單位被加入。

✅ 解題思路

  1. 原本 AddItem 回傳 bool,只能表示成功/失敗,資訊不足。
  2. 改為回傳 error,將錯誤原因傳遞出去。

程式片段

func AddItem(bill, units map[string]int, item, unit string) error {
    qty, ok := units[unit]
    if !ok {
        return fmt.Errorf("不存在的單位: %s", unit)
    }
    bill[item] += qty
    return nil
}

測試:

err := AddItem(bill, units, "orange", "mega_gross")
if err != nil {
    fmt.Println(err) // ❌ 不存在的單位: mega_gross
}

👉 答案: 呼叫時會輸出錯誤,而不會亂塞進帳單。


錯誤題 2:退貨比買的還多

顧客說:「我要退 2 打香蕉啦!」
結果,實際上他只買了半打。

👉 請你修改 RemoveItem,讓它能檢查數量不足並回傳錯誤訊息。

程式片段

func RemoveItem(bill, units map[string]int, item, unit string) error {
    qty, ok := units[unit]
    if !ok {
        return fmt.Errorf("不存在的單位: %s", unit)
    }
    current, exists := bill[item]
    if !exists {
        return fmt.Errorf("帳單上沒有 %s", item)
    }
    if current < qty {
        return fmt.Errorf("退貨數量太多 (現有 %d, 退 %d)", current, qty)
    }
    if current == qty {
        delete(bill, item)
    } else {
        bill[item] -= qty
    }
    return nil
}

測試:

err := RemoveItem(bill, units, "banana", "dozen")
if err != nil {
    fmt.Println(err) 
    // ❌ 退貨數量太多 (現有 6, 退 12)
}

👉 答案: 傳回錯誤提示,避免出現「負數存貨」。


錯誤題 3:查詢不存在的商品

顧客問:「老闆,我帳單裡有葡萄嗎?」
但實際上他從來沒買過葡萄。

👉 請你修改 GetItem,讓它在查不到商品時回報錯誤。

程式片段

func GetItem(bill map[string]int, item string) (int, error) {
    qty, ok := bill[item]
    if !ok {
        return 0, fmt.Errorf("帳單上沒有 %s", item)
    }
    return qty, nil
}

測試:

qty, err := GetItem(bill, "grape")
if err != nil {
    fmt.Println(err) // ❌ 帳單上沒有 grape
}

👉 答案: 程式輸出錯誤,避免誤以為有這個商品。


錯誤題 4:統一管理錯誤

錯誤訊息太多時,老闆決定寫一個小工具,統一印出 log

程式片段

import "log"

func CheckErr(err error) {
    if err != nil {
        log.Println("❌", err)
    }
}

測試:

err := AddItem(bill, units, "pear", "super_gross")
CheckErr(err)
// log: ❌ 不存在的單位: super_gross

👉 答案: 錯誤訊息整齊一致,未來也方便擴充(例如記錄寫進檔案、丟到監控系統)。


📝 總結

  1. 為什麼要錯誤處理?

    • 防止無效單位
    • 避免退貨超量
    • 查詢時能即時提醒
  2. 設計要點

    • 把原本 bool 替換成 error,訊息更清楚。
    • 使用 CheckErr 幫手,讓程式看起來更乾淨。
  3. 小老闆的心得

    「以前帳單常常亂掉,現在加了錯誤處理,顧客怎麼刁難我都能穩穩守住!」 🎉

📦 主程式 (錯誤處理版示範)


package main

import (
    "fmt"
    "log"
)

// -----------------------------
// 基礎函式
// -----------------------------
func Units() map[string]int {
    return map[string]int{
        "quarter_of_a_dozen": 3,
        "half_of_a_dozen":    6,
        "dozen":              12,
        "small_gross":        120,
        "gross":              144,
        "great_gross":        1728,
    }
}

func NewBill() map[string]int {
    return map[string]int{}
}

// -----------------------------
// 改良後(帶錯誤訊息)
// -----------------------------
func AddItem(bill, units map[string]int, item, unit string) error {
    qty, ok := units[unit]
    if !ok {
        return fmt.Errorf("不存在的單位: %s", unit)
    }
    bill[item] += qty
    return nil
}

func RemoveItem(bill, units map[string]int, item, unit string) error {
    qty, ok := units[unit]
    if !ok {
        return fmt.Errorf("不存在的單位: %s", unit)
    }
    current, exists := bill[item]
    if !exists {
        return fmt.Errorf("帳單上沒有 %s", item)
    }
    if current < qty {
        return fmt.Errorf("退貨數量太多 (現有 %d, 退 %d)", current, qty)
    }
    if current == qty {
        delete(bill, item)
    } else {
        bill[item] -= qty
    }
    return nil
}

func GetItem(bill map[string]int, item string) (int, error) {
    qty, ok := bill[item]
    if !ok {
        return 0, fmt.Errorf("帳單上沒有 %s", item)
    }
    return qty, nil
}

// 小幫手
func CheckErr(err error) {
    if err != nil {
        log.Println("❌", err)
    }
}

// -----------------------------
// 主程式
// -----------------------------
func main() {
    units := Units()
    bill := NewBill()

    fmt.Println("== 加入一打蘋果 ==")
    err := AddItem(bill, units, "apple", "dozen")
    CheckErr(err)
    fmt.Println("bill:", bill)

    fmt.Println("== 試著加入不存在的單位 ==")
    err = AddItem(bill, units, "orange", "mega_gross")
    CheckErr(err)

    fmt.Println("== 退貨比買的還多 ==")
    err = RemoveItem(bill, units, "apple", "great_gross")
    CheckErr(err)

    fmt.Println("== 查詢不存在的商品 ==")
    _, err = GetItem(bill, "grape")
    CheckErr(err)
}

📝 執行效果 (預期)

== 加入一打蘋果 ==
bill: map[apple:12]
== 試著加入不存在的單位 ==
❌ 不存在的單位: mega_gross
== 退貨比買的還多 ==
❌ 退貨數量太多 (現有 12, 退 1728)
== 查詢不存在的商品 ==
❌ 帳單上沒有 grape

上一篇
Day 5 : Go語言 slice 與 map - 延伸練習HW 2
下一篇
Day 7 : Go 指標基礎 範例:選舉計票系統入門
系列文
後端攻略筆記13
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言