什么是"模式"
在 Swift 中,模式(Pattern) 描述了一个值的结构,而不是具体的某个值。
借助模式,我们可以:
- 检查某个值是否符合该结构(匹配)
- 把符合结构的值拆解出来,绑定到新的变量 / 常量(绑定)
模式出现的常见场景:
- 变量 / 常量声明:
let (x, y) = point switch的case标签if/guard/while/for-in的条件catch异常捕获
Swift 将模式分为两大类:
| 类别 | 特点 | 典型模式 |
|---|---|---|
| 必然匹配型 | 只要类型对,就一定成功,不会运行时失败 | 通配符、标识符、元组、值绑定 |
| 可能失败型 | 运行时才知是否匹配,可能走 default 分支 |
枚举 case、可选、类型转换、表达式 |
必然匹配型模式
通配符模式(Wildcard Pattern)
写法:一个下划线 _
作用:匹配并丢弃任意值,常用于"我不关心"的场景。
swift
// 只想循环 3 次,不需要索引
for _ in 1...3 {
print("拍一张")
}
标识符模式(Identifier Pattern)
写法:一个变量 / 常量名
作用:匹配任意值,并把它绑定到该名字。
swift
let someValue = 42 // someValue 就是标识符模式
注意:当标识符出现在赋值左侧时,它隐含地被包装在一个"值绑定模式"里。
值绑定模式(Value-Binding Pattern)
写法:以 let / var 开头,可"分发"到子模式
作用:把匹配到的值绑定到新的变量 / 常量。
swift
let point = (3, 4)
switch point {
case let (x, y): // let 分发到 x、y
print("坐标:(\(x), \(y))")
default:
break
}
// 等价于 case (let x, let y):
元组模式(Tuple Pattern)
写法:圆括号包裹的"零个或多个子模式"列表
作用:按结构匹配元组;可嵌套;可带类型标注做类型约束。
swift
// 1. 基本拆解
let (a, b) = (1, 2)
// 2. 类型约束:只能匹配 (Int, Int)
let (x, y): (Int, Int) = (3, 4)
// 3. 嵌套 + 通配符
let rgb = (r: 255, g: 60, b: 90)
switch rgb {
case (let r, _, _): // 只要红色分量
print("红色值 = \(r)")
default:
break
}
⚠️ 限制:当元组模式用于 for-in / 变量声明时,子模式只能是:通配符、标识符、可选、元组,不能是表达式。
因此下面代码非法:
swift
let (x, 0) = (5, 0) // 0 是表达式模式,编译报错
可能失败型模式
枚举 case 模式(Enumeration Case Pattern)
写法:.caseName 或 EnumType.caseName,有关联值时再跟元组
作用:匹配具体某个枚举成员;可一并提取关联值。
swift
enum NetworkResponse {
case success(body: String)
case failure(code: Int, message: String)
}
let res: NetworkResponse = .success(body: "OK")
switch res {
case .success(let body):
print("成功:\(body)")
case .failure(let code, let msg):
print("错误 \(code):\(msg)")
}
小技巧:Swift 把 Optional 也当成枚举,因此 .some / .none 可与其自定义枚举混用:
swift
enum NetworkResponse {
case success(body: String)
case failure(code: Int, message: String)
}
let maybe: NetworkResponse? = .success(body: "Maybe")
switch maybe {
case .success(let body): // 省略 .some 写法
print(body)
case .failure(_, _):
print("失败")
case .none:
print("无值")
}
可选模式(Optional Pattern)
写法:在标识符后加 ?
本质:语法糖,等价于 .some(wrapped) 的枚举 case 模式
场景:快速解包数组 / 字典里的可选值
swift
let nums: [Int?] = [1, nil, 3, nil, 5]
for case let num? in nums { // 只遍历非 nil
print(num) // 输出 1 3 5
}
类型转换模式(Type-Casting Pattern)
| 模式 | 出现位置 | 作用 |
|---|---|---|
is Type |
仅 switch 的 case |
判断运行时类型是否匹配,不绑定新名 |
pattern as Type |
switch / if / guard ... |
判断并强转,匹配成功则绑定到新模式 |
swift
let mixed: [Any] = [1, "hi", 3.14, 40]
for element in mixed {
switch element {
case is String:
print("遇到字符串")
case let i as Int where i > 30:
print("大于 30 的整数:\(i)")
default:
break
}
}
表达式模式(Expression Pattern)
写法:任意表达式
原理:Swift 使用标准库里的 ~= 运算符做匹配;默认实现用 ==,但可重载实现自定义规则。
swift
let count = 7
// 默认行为:相等比较
switch count {
case 0:
print("零")
default:
print("非零")
}
// 自定义 ~=,让字符串也能匹配整数
func ~= (pattern: String, value: Int) -> Bool {
return pattern == "\(value)"
}
switch count {
case "7": // 自定义后返回 true
print("幸运数字 7")
default:
break
}
利用重载,可实现"范围匹配"、"正则匹配"、"自定义业务规则匹配"等高级玩法。
一个综合示例:把模式用活
swift
// 1. 定义模型
enum Command {
case move(x: Int, y: Int)
case pen(up: Bool)
case repeatTimes(times: Int, [Command]) // 嵌套命令
}
// 2. 解析脚本
let scripts: [Command?] = [
.move(x: 10, y: 20),
nil,
.repeatTimes(times: 2, [.pen(up: true), .move(x: 5, y: 0)])
]
// 3. 深度遍历,模式一网打尽
func walk(_ cmds: [Command?]) {
for case let cmd? in cmds { // 可选模式去 nil
switch cmd {
// 3.1 关联值直接拆出
case .move(let x, let y):
print("移动 to (\(x), \(y))")
// 3.2 布尔判断
case .pen(up: true):
print("抬笔")
case .pen(up: false):
print("落笔")
// 3.3 嵌套递归
case .repeatTimes(times: let n, let sub):
print("开始重复 \(n) 次")
for _ in 0..<n { walk(sub) } // 递归
}
}
}
walk(scripts)
输出: 移动 to (10, 20) 开始重复 2 次 抬笔 移动 to (5, 0) 抬笔 移动 to (5, 0)
总结与扩展思考
-
模式是 Swift 的"静态检查 + 运行时匹配"双保险
编译期保证结构合法;运行期再决定走哪条分支,既安全又灵活。
-
用好"必然匹配"能少写样板代码
例如
let (x, y) = point一行完成解构;for case let num?一行完成解包过滤。 -
"可能失败"模式让业务语义显性化
把"枚举 case、类型判断、可选解包"统统搬进
switch,代码即文档,可读性远高于一堆if else。 -
重载
~=是隐藏大杀器正则、范围、区间、甚至"数据库记录是否存在"都可以抽象成模式,配合
switch写出声明式代码。 -
模式不仅存在于语法,更存在于设计
把"什么结构合法"提前定义成枚举 / 元组 / 协议,再用模式去匹配,天然契合"非法状态无法表示"的 Swift 哲学。