iT邦幫忙

2025 iThome 鐵人賽

DAY 17
0
Modern Web

後端攻略筆記系列 第 17

Day 17 : Go 基礎篇總複習

  • 分享至 

  • xImage
  •  

用超市購物籃學會 Go:從 slice、map 到 interface 的完整教學

程式語言學習如果只碰語法,很難感受到學習的樂趣。這篇文章將從日常「去超市買水果」的生活例子展開,帶你循序漸進地理解 Go 的 slice、map、for 迴圈、struct、interface 等核心訊息,並在過程中逐步加入越來越複雜的業務邏輯挑戰,讓學習更有成就感與實戰感。


1. 建立商品結構與購物籃 (slice)

首先,我們要為「商品」設計一個 struct,包括名字、價格、數量。再利用 slice 來表示購物籃,裡面裝著每一樣買的商品。

type Product struct {
    Name  string
    Price int
    Qty   int
}

func main() {
    basket := []Product{
        {"Apple", 10, 3},
        {"Banana", 5, 6},
        {"Watermelon", 50, 1},
    }
    fmt.Println("購物籃:", basket)
}

此時購物籃是有序的商品列表,我們可以用 for 迴圈逐項處理:

total := 0
for _, item := range basket {
    total += item.Price * item.Qty
    fmt.Printf("買了 %d 個 %s,單價 %d\n", item.Qty, item.Name, item.Price)
}
fmt.Println("總金額:", total)

2. 使用 map 儲存價格表,並實現購物籃商品更新

在超市,價格表經常用來查找商品的單價。我們用 map[string]int 來表示。

當顧客再次購買同一商品時,不是新增一個商品,而是更新數量。以下示範如何用 slice + for 搭配實現查找和更新:

priceList := map[string]int{
    "Apple":  10,
    "Banana": 5,
    "Milk":   30,
}

func addOrUpdateCart(cart []Product, prod Product) []Product {
    for i, item := range cart {
        if item.Name == prod.Name {
            cart[i].Qty += prod.Qty
            return cart
        }
    }
    return append(cart, prod)
}

func main() {
    cart := []Product{}
    cart = addOrUpdateCart(cart, Product{"Apple", priceList["Apple"], 3})
    cart = addOrUpdateCart(cart, Product{"Banana", priceList["Banana"], 2})
    cart = addOrUpdateCart(cart, Product{"Apple", priceList["Apple"], 2}) // 更新 Apple 數量
    
    fmt.Println(cart)
}

這讓我們實作了更接近真實購物情境的商品更新。


3. 進階 for 與巢狀迴圈:篩選與促銷清單比對

假設商店有促銷清單,只打折促銷商品,我們需掃描購物籃並比對促銷清單,計算折扣後的價格。

promoList := []string{"Apple", "Milk"}

for _, prod := range cart {
    discount := 0.0
    for _, promoItem := range promoList {
        if prod.Name == promoItem {
            discount = 0.1 // 10% 折扣
            break
        }
    }
    priceAfterDiscount := int(float64(prod.Price) * (1 - discount))
    fmt.Printf("%s 原價 %d,折扣後 %d\n", prod.Name, prod.Price, priceAfterDiscount)
}

巢狀迴圈幫助實現了促銷商品的比對,讓程式更靈活能面對複雜業務。


4. 介面 (interface) 設計,支持多樣商品結帳

不同類別商品(水果、飲料、零食)可能有不同計價邏輯。我們用 interface 抽象「結帳物件」:

type Checkoutable interface {
    Total() int
}

type Product struct {
    Name     string
    Price    int
    Qty      int
    Discount float64
}

func (p Product) Total() int {
    return int(float64(p.Price)*(1-p.Discount)) * p.Qty
}

type Drink struct {
    Name  string
    Price int
    Qty   int
    Size  string // 不同容量,不同價格策略
}

func (d Drink) Total() int {
    // 比如大杯多 10 元
    extra := 0
    if d.Size == "Large" {
        extra = 10
    }
    return (d.Price + extra) * d.Qty
}

func main() {
    var cart []Checkoutable
    cart = append(cart, Product{"Apple", 10, 3, 0.1})
    cart = append(cart, Drink{"Cola", 15, 2, "Large"})

    total := 0
    for _, item := range cart {
        total += item.Total()
    }
    fmt.Println("總金額:", total)
}

這樣購物籃可以裝不同商品,也能用同一種方式結帳。


5. 挑戰題:交易紀錄與多賣家付款

最後,我們設計一個交易系統,支援多賣家,多筆購買紀錄與不同付款方式:

type Purchase struct {
    Item Checkoutable
    Shop string
}

type PaymentMethod interface {
    Pay(amount int)
}

type CreditCard struct{ Number string }
func (c CreditCard) Pay(amount int) {
    fmt.Printf("使用信用卡付款 %d 元,卡號 %s\n", amount, c.Number)
}

type Cash struct{}
func (c Cash) Pay(amount int) {
    fmt.Printf("使用現金付款 %d 元\n", amount)
}

func main() {
    purchases := map[string][]Purchase{
        "FreshMart": {
            {Product{"Apple", 10, 5, 0.1}, "FreshMart"},
            {Product{"Milk", 30, 1, 0}, "FreshMart"},
        },
        "SuperShop": {
            {Drink{"Cola", 15, 2, "Large"}, "SuperShop"},
        },
    }

    total := 0
    for _, records := range purchases {
        for _, p := range records {
            total += p.Item.Total()
        }
    }

    var payMethod PaymentMethod = CreditCard{"1234-5678-9876-5432"}
    payMethod.Pay(total)
}

交易清楚紀錄每家賣家的購買明細,付款方式彈性可擴展。



上一篇
Day 16 : 用 Go 語言的 for 迴圈,輕鬆解決生活中的重複工作
系列文
後端攻略筆記17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言