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` 輔助產生。