Enum的威,Enum的力,Enum的威力,一粒????
你看棒球比賽嗎? 棒球是我們台灣的國球,在台灣有許許多多的球迷,筆者也從國中時代開始,就深深地感受到棒球的魅力,不論是下課回家盯著電視,或者直接走進棒球場,享受著棒球帶來的熱血與激情!
How can you not be romantic about baseball?
在這篇文章中,我們將走進棒球場中,帶你一步步認識 Swift 中 Enum 的特性,感受棒球場上的 Swift Moment。
從最基本的定義,到進階的 Nested Enum,Associated Value,最後再介紹如何透過 CustomStringConvertible 來嘗試製作比賽紀錄。
這些技巧不只能幫助你寫出更有結構的程式,也讓你對 Enum 有更深入的理解。
從守備位置認識 Enum 的基本特性
讓我們先從最基本的定義開始吧!
Swift 的 Enum 非常適合用來表示 「狀態有限、規則清晰」 的資料。
什麼是 「狀態有限、規則清晰」 ?
舉例來說,一場棒球比賽中,一隊有九個守備位置,每個位置名稱固定、不會重複,也不會出現第十種或-1種位置,這正好適合用 Enum 來表示。
enum FieldPosition {
case pitcher
case catcher
case firstBase
case secondBase
case thirdBase
case shortstop
case leftField
case centerField
case rightField
}
每一個 case 就像一位選手的位置,它的名稱唯一、型別固定,能幫助我們用程式清楚表達狀態,避免寫錯。
俄羅斯套娃的 Nested Enum !?進一步分類守備位置
當我們希望更進一步區分內野、外野、其他守備角色時,就可以使用巢狀 Enum(nested enum)。這可以幫助我們把不同類型的守備位置分門別類地整理起來。
enum PositionGroup {
enum Battery: Int {
case pitcher = 1
case catcher = 2
}
enum Infield: Int {
case firstBase = 3
case secondBase = 4
case thirdBase = 5
case shortstop = 6
}
enum Outfield: Int {
case leftField = 7
case centerField = 8
case rightField = 9
}
case battery(Battery)
case infield(Infield)
case outfield(Outfield)
}
這裡除了做分類,也幫每個位置標上了守備紀錄常用的編號,方便日後進行進一步紀錄。
使用 Associated Aalue 來描述打擊結果
Swift 的 Enum 也能為每個 case 搭配額外資訊,讓 Enum 更靈活,如同我們上面用到的 case battery(Battery),這就是 Associated Value 的一種。
我們可以進一步設計一個 Enum 來描述打擊結果,並且使用 Associated Value 來描述打擊結果的細節。
enum BattingResult {
case strikeOut
case flyOut(to: FieldPosition)
case groundOut(to: FieldPosition)
case hit(HitType)
case doublePlay(involvedFielders: [FieldPosition])
case error(by: FieldPosition)
enum HitType {
case single
case double
case triple
case homeRun
}
}
Associated Value 除了 Enum 之外,也可以放入其他型別,例如 Int、String、Bool 或者自定義的 class 或 struct。
這樣的設計讓 enum 更有彈性,可以根據不同情況儲存對應的資料。
CaseIterable:我要全部!
如果我們希望列出某個 Enum 所有的 case,可以讓它遵守 CaseIterable。
enum FieldPosition: CaseIterable {
case pitcher, catcher, firstBase, secondBase, thirdBase, shortstop, leftField, centerField, rightField
}
for position in FieldPosition.allCases {
print(position)
}
這對製作選單、驗證資料、或者在單元測試中產生所有可能值非常實用。
用 CustomStringConvertible 讓 Enum 更容易紀錄與顯示
當我們需要把 Enum 的值用文字清楚地表達出來(例如做 log 或畫面顯示),可以透過遵守 CustomStringConvertible 協定來達成。
當我們的 Enum 遵守 CustomStringConvertible 時,需要加上 description 的實作來滿足 CustomStringConvertible 協定。
extension FieldPosition: CustomStringConvertible {
var description: String {
switch self {
case .pitcher: return "投手"
case .catcher: return "捕手"
case .firstBase: return "一壘手"
case .secondBase: return "二壘手"
case .thirdBase: return "三壘手"
case .shortstop: return "游擊手"
case .leftField: return "左外野手"
case .centerField: return "中外野手"
case .rightField: return "右外野手"
}
}
}
除了 FieldPosition,我們也可以幫打擊結果加上描述:
extension BattingResult: CustomStringConvertible {
var description: String {
switch self {
case .strikeOut:
return "三振"
case .flyOut(let to):
return "飛球出局(由 \(to) 接殺)"
case .groundOut(let to):
return "滾地球出局(由 \(to) 處理)"
case .hit(let type):
return "打出一支 \(type)"
case .doublePlay(let involvedFielders):
let sequence = involvedFielders.map { "\($0.rawValue)" }.joined(separator: "-")
return "雙殺 \(sequence)"
case .error(let by):
return "守備失誤(由 \(by))"
}
}
}
extension BattingResult.HitType: CustomStringConvertible {
var description: String {
switch self {
case .single: return "一壘安打"
case .double: return "二壘安打"
case .triple: return "三壘安打"
case .homeRun: return "全壘打"
}
}
}
這樣我們就可以清楚紀錄像是:
let result1: BattingResult = .doublePlay(involvedFielders: [.shortstop, .secondBase, .firstBase])
print(result1.description) // 雙殺 6-4-3
let result2: BattingResult = .hit(.single)
print(result2.description) // 打出一支 一壘安打
let result3: BattingResult = .strikeOut
print(result3.description) // 三振
用這種方式,我們可以靈活記錄比賽過程中發生的各種狀況,也讓程式碼更有可讀性與可維護性。
以上,我的第一篇方格子 Swift 教學文章,我們用棒球場上的守備位置、打擊結果、以及比賽過程,介紹了Enum 的基本特性,以及如何透過 CustomStringConvertible 來讓 Enum 更容易紀錄與顯示。
這些技巧不只能幫助你寫出更有結構的程式,也讓你對 Enum 有更深入的理解。
希望這篇文章能夠幫助你更了解 Enum 的威力,有時間的話也不妨走進球場,感受棒球帶來的熱血與激情!
如果還有其他你發現的 Swift Moment,也歡迎留言分享,多多交流!
*本篇文章程式碼部分由 `AI` 輔助產生。






















