枚举与模式匹配
本教程共 93 篇 · 第 50 篇 · 更新于 2026-08-08 · 约 8 分钟阅读
本节目标:读完你掌握 switch 对枚举的穷尽匹配、值绑定、where 过滤,以及 if case / guard case 等配套写法。
1-1 穷尽性是一切的基础
前面提过,switch 匹配枚举必须覆盖所有成员,否则编译报错。这条规则的价值在于:当你新增一个成员,所有遗漏的 switch 立刻暴露,逼你把新情况补上。这是枚举最大的安全感来源,也是 Swift 强调”编译期防错”的体现。相比之下,用 if 链判断整数状态时,漏掉某个值编译器可不会提醒你。
1-2 值绑定模式
枚举成员带关联值时,可在 case 里用 let/var 把数据绑成局部名字,这叫”值绑定”:
enum ScreenState {
case loading
case success(data: String)
case failed(code: Int, message: String)
}
let state = ScreenState.failed(code: 500, message: "服务器开小差")
switch state {
case .loading:
print("加载中")
case .success(let data):
print("拿到数据:\(data)")
case .failed(let code, let message):
print("出错 \(code):\(message)")
}
值绑定让你在分支内部直接使用解出来的数据,不必再额外取值。如果成员在定义时给关联值起了名字(如 data:、code:),switch 里照样用 let 重新命名即可,原来的外部标签只用于创建时可读,不影响解构。
1-3 用 where 追加条件
有时成员一样,但你想按关联值再细分。用 where 加额外判断:
enum Movement {
case walk(Int)
case run(Int)
}
let m = Movement.run(12)
switch m {
case .walk(let speed) where speed < 5:
print("慢走")
case .walk(let speed):
print("快走,速度 \(speed)")
case .run(let speed) where speed > 10:
print("冲刺,速度 \(speed)")
case .run(let speed):
print("慢跑,速度 \(speed)")
}
where 让同一个成员能再分多支,注意要把更具体的条件写在前面,否则会被前面的宽松分支先截走。比如把 .walk(let speed) 写在 .walk(let speed) where speed < 5 前面,那么小于 5 的也会走宽松分支,细分就失效了。
1-4 if case 与 guard case
只想判断某一种成员时用 if case;在函数中想”不满足就提前返回”则用 guard case:
if case .success(let data) = state {
print("数据:\(data)")
}
func handle(_ s: ScreenState) {
guard case .failed(let code, let message) = s else {
return
}
print("失败 \(code):\(message)")
}
guard case 的好处是解构出来的值(code、message)在后续代码里直接可用,不用再包一层 if。它和 if case 逻辑相同,只是控制流更顺,特别适合”非法状态直接退出、合法状态继续往下走”的函数开头。
1-5 元组与枚举混合匹配
switch 还能匹配元组,枚举和元组组合能做更细的分支。比如同时判断方向和距离:
enum Direction { case north, south, east, west }
let trip = (Direction.north, 3)
switch trip {
case (.north, let km) where km > 2:
print("往北走了较远 \(km) 公里")
case (.north, _):
print("往北")
default:
break
}
下划线 _ 表示”这个位置的值我不在意”,只用来占位。元组模式常和枚举配合,用来一次检查多个维度(方向 + 距离、状态码 + 消息),让分支条件一目了然。
1-6 枚举的嵌套匹配
枚举成员还可以带枚举类型的关联值,形成两层匹配。比如外层是”操作结果”,里层是”错误种类”,switch 可以一层层剥开。这种写法在处理复杂状态时尤为清晰,因为它把”先判大类、再判小类”的过程直接写进模式里。
1-7 模式匹配的更多可能性
Swift 的模式不止值绑定和 where。你还能在 case 里用区间(如 case .level(let n) where n > 0 && n < 10)、用元组一次匹配多个值、甚至在 case 条件里再嵌模式。枚举因为是封闭集合,和这些模式配合尤其稳:编译器知道总共就那几个成员,能帮你检查有没有覆盖全。
这种组合在解析外部数据时很实用。比如一个”响应”枚举,success 带数据、failure 带错误码,配合 where 还能按错误码范围分流(4xx 走客户端错、5xx 走服务端错),逻辑写在一处,读起来一目了然。
1-8 常见误用
新手常犯两个错:一是忘了穷尽,没写 default 又漏了成员,编译直接报错——这不是坏事,按提示补上即可;二是把 let 绑定的名字和外面变量撞名,导致作用域混乱。
养成”绑定名简短、贴合语义”的习惯(如 code、message、data),能少踩很多坑。另外,where 条件永远写在对应 case 后,不要错写到别的分支,否则细分逻辑会错位。
1-9 用模式匹配替代一长串 if
没有模式匹配时,处理枚举状态往往写成一堆 if x == .a { } else if x == .b { }。这种写法既不能保证穷尽,也不方便解构关联值。switch 配合值绑定和 where,把”判断种类 + 取数据 + 细分条件”三件事合一,代码更短也更安全。
建议养成习惯:只要操作对象是枚举,优先考虑 switch,而不是 if 链。编译器会替你盯着有没有漏掉成员,这份安全感是 if 链给不了的。
1-10 枚举模式匹配的实用直觉
把枚举当”状态机”来用,模式匹配就特别顺。比如界面状态 loading / success / failed,用 switch 一写,每种状态该显示什么、带什么数据,都收在一个地方。比起散布各处的 if 判断,这种写法让”状态到行为”的映射一目了然,也方便你检查有没有遗漏的状态分支。
当枚举成员带关联值时,模式匹配还能顺手把数据取出来直接用,省去再写取值代码。把”判断 + 取数”合二为一,是 Swift 枚举最舒服的地方。
1-11 枚举的模式匹配是编译期保障
重申一个关键点:switch 对枚举的穷尽检查发生在编译期。这意味着”漏处理某个成员”这种 bug,在你敲完代码、还没运行之前,编译器就帮你拦下了。对大型项目、对频繁改动的代码,这种”改一个枚举,所有相关 switch 被迫更新”的机制,是极为省心的保险。
相比之下,用整数或字符串表示状态时,漏判只会在运行时暴露,甚至埋藏很久才发作。枚举 + 模式匹配把这类风险提前到了编译期,这正是 Swift 强调安全的核心体现。
1-12 小结前的最后提醒
模式匹配的学习曲线在前几章就铺好了:可选类型的 if let、switch 的区间匹配,都是同一套”模式”思想的延伸。枚举把这套思想用到极致——封闭的成员集合 + 关联值,让 switch 既是判断也是解构。把前面学的模式知识串起来,你会发现它们一脉相承。
1-13 小结
枚举与模式匹配是 Swift 的强项。switch 穷尽保证不漏判;值绑定把关联值取出使用;where 在成员内再细分,记得具体条件在前;if case / guard case 适合只关心一种成员的场景,guard case 还能让解出的数据在后续直接用。熟练掌握这些,处理状态、解析数据会非常顺手。下一模块进入结构体。