在前面的篇章,我們用指標成功解決了計票問題。但現在,選舉委員會有了新需求:
「除了票數,我們還要記錄每位候選人的 政黨、競選口號,並判斷是否當選。」
如果只用之前學的變數,可能會變成這樣:
// ❌ 這樣管理資料太亂了!
var names = []string{"張三", "李四"}
var votes = []int{1247, 1156}
var parties = []string{"民主黨", "進步黨"}
➡️ 問題:資料零散,非常容易出錯,而且很難維護。
這時候,我們需要一個「打包盒」,把同一個候e選人的所有資料都裝在一起。
在 Go 語言中,struct
(結構體) 就是這個打包盒。我們可以自訂盒子的格式:
type ElectionResult struct {
Name string // 候選人姓名
VoteCount int // 得票數
Party string // 政黨
Slogan string // 競選口號
IsElected bool // 是否當選
}
現在,一個候選人的所有資訊,都整齊地放在 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
把複雜的資料打包,並用方法讓資料「動起來」。