iT邦幫忙

2025 iThome 鐵人賽

DAY 9
0
Modern Web

後端攻略筆記系列 第 9

Day 9 : Go 指標與結構 — 篇三:結構體(struct)與選舉系統案例實作

  • 分享至 

  • xImage
  •  

Go 指標與結構 — 篇三:結構體(struct)與選舉系統案例實作

為什麼需要結構體?從複雜的選舉資料談起

在前面的篇章,我們用指標成功解決了計票問題。但現在,選舉委員會有了新需求:

「除了票數,我們還要記錄每位候選人的 政黨、競選口號,並判斷是否當選。」

如果只用之前學的變數,可能會變成這樣:

// ❌ 這樣管理資料太亂了!
var names = []string{"張三", "李四"}
var votes = []int{1247, 1156}
var parties = []string{"民主黨", "進步黨"}

➡️ 問題:資料零散,非常容易出錯,而且很難維護。

這時候,我們需要一個「打包盒」,把同一個候e選人的所有資料都裝在一起。


Go 的 struct:資料的「打包盒」

在 Go 語言中,struct (結構體) 就是這個打包盒。我們可以自訂盒子的格式:

type ElectionResult struct {
    Name      string // 候選人姓名
    VoteCount int    // 得票數
    Party     string // 政黨
    Slogan    string // 競選口號
    IsElected bool   // 是否當選
}

現在,一個候選人的所有資訊,都整齊地放在 ElectionResult 這個盒子裡了!


建立和使用 ElectionResult

建立和使用這個「盒子」非常簡單:

func main() {
    // 建立一個張三的盒子
    candidate1 := ElectionResult{
        Name:      "張三",
        VoteCount: 1247,
        Party:     "民主黨",
        Slogan:    "為民服務,創造未來",
        IsElected: true,
    }

    // 讀取盒子的資料
    fmt.Println(candidate1.Name)    // 張三
    fmt.Println(candidate1.Party)   // 民主黨
}

為了標準化建立流程,我們可以寫一個「建構函式」:

func NewElectionResult(name, party, slogan string) *ElectionResult {
    return &ElectionResult{
        Name:      name,
        Party:     party,
        Slogan:    slogan,
        VoteCount: 0,     // 初始票數為 0
        IsElected: false, // 預設未當選
    }
}

為結構體加上方法:讓資料會「做事」

struct 不只能裝東西,我們還能教它「做事」,也就是為它加上 方法 (method)

// 為 ElectionResult 加上「加票」的方法
func (er *ElectionResult) AddVotes(votes int) {
    if votes > 0 {
        er.VoteCount += votes
    }
}

// 加上「判定當選」的方法
func (er *ElectionResult) DetermineElection(threshold int) {
    if er.VoteCount >= threshold {
        er.IsElected = true
    }
}

注意:這裡的 (er *ElectionResult) 叫做 指標接收者。使用指標才能確保我們是 修改原始的盒子,而不是修改複製品。


完整的選舉管理系統

現在,讓我們把所有概念整合起來,打造一個專業的選舉管理系統!

package main

import (
    "fmt"
    "sort"
)

// 選舉結果的「打包盒」
type ElectionResult struct {
    Name      string
    VoteCount int
    Party     string
    Slogan    string
    IsElected bool
}

// 建立候選人資料
func NewElectionResult(name, party, slogan string) *ElectionResult {
    return &ElectionResult{Name: name, Party: party, Slogan: slogan}
}

// 加票方法
func (er *ElectionResult) AddVotes(votes int) {
    if votes > 0 {
        er.VoteCount += votes
    }
}

// 整個選舉系統的管理中心
type ElectionSystem struct {
    Title      string
    Candidates []*ElectionResult
}

// 建立新的選舉系統
func NewElectionSystem(title string) *ElectionSystem {
    return &ElectionSystem{
        Title:      title,
        Candidates: []*ElectionResult{},
    }
}

// 註冊候選人
func (es *ElectionSystem) AddCandidate(name, party, slogan string) {
    newCandidate := NewElectionResult(name, party, slogan)
    es.Candidates = append(es.Candidates, newCandidate)
    fmt.Printf("✓ %s (%s) 已登記參選!\n", name, party)
}

// 投票
func (es *ElectionSystem) CastVotes(candidateName string, votes int) {
    for _, candidate := range es.Candidates {
        if candidate.Name == candidateName {
            candidate.AddVotes(votes)
            return
        }
    }
}

// 結束選舉並公布結果
func (es *ElectionSystem) FinalizeAndShowResults() {
    fmt.Printf("\n🏁 %s 正式結束!\n\n", es.Title)

    // 根據票數排序
    sort.Slice(es.Candidates, func(i, j int) bool {
        return es.Candidates[i].VoteCount > es.Candidates[j].VoteCount
    })

    fmt.Println("=== 最終選舉結果 ===")
    for i, candidate := range es.Candidates {
        fmt.Printf("第 %d 名:%s (%s) - %d 票\n",
            i+1, candidate.Name, candidate.Party, candidate.VoteCount)
    }
}

func main() {
    // 建立一場選舉
    election := NewElectionSystem("2025 年社區主席選舉")

    // 候選人登記
    election.AddCandidate("張三", "民主黨", "為民服務,創造未來!")
    election.AddCandidate("李四", "進步黨", "改革創新,共創繁榮!")
    election.AddCandidate("王五", "改革黨", "穩健前進,造福人民!")

    // 開始投票
    fmt.Println("\n=== 投票進行中... ===")
    election.CastVotes("張三", 1247)
    election.CastVotes("李四", 1156)
    election.CastVotes("王五", 987)

    // 公布結果
    election.FinalizeAndShowResults()
}

輸出結果:

✓ 張三 (民主黨) 已登記參選!
✓ 李四 (進步黨) 已登記參選!
✓ 王五 (改革黨) 已登記參選!

=== 投票進行中... ===

🏁 2025 年社區主席選舉 正式結束!

=== 最終選舉結果 ===
第 1 名:張三 (民主黨) - 1247 票
第 2 名:李四 (進步黨) - 1156 票
第 3 名:王五 (改革黨) - 987 票

全系列總結:從指標到結構體的旅程

透過這三篇文章,我們用「選舉計票」這個例子,完成了從新手到入門的旅程:

  • 篇一學會了「指標」:知道如何用 &* 來讀取和修改「地址」上的資料。
  • 篇二學會了「安全操作」:懂得用 nil 判斷來避免程式崩潰,並透過封裝保護資料。
  • 篇三學會了「結構體」:學會用 struct 把複雜的資料打包,並用方法讓資料「動起來」。


上一篇
Day 8 : Go 指標與結構 — 篇二:處理指標的 Nil 判斷與安全操作技巧
下一篇
Day 10 : Struct入門 - 用「遙控車」搞懂什麼是 Struct!
系列文
後端攻略筆記13
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言