Swift 控制流深度解析(一):循环、条件与分支

为什么 Swift 的控制流值得单开一篇?

  1. 语法糖多:区间、stride、tuple、where、guard、defer......
  2. 安全严苛:switch 必须 exhaustive、case 不能空、默认不贯穿。
  3. 表达能力强:if/switch 可以当表达式用,一行赋值即可。
  4. 场景丰富:从日常循环到资源清理、API 可用性检查,全覆盖。

For-In 循环:从"会写"到"写对"

基本形态

swift 复制代码
// 遍历数组
let fruits = ["apple", "orange", "banana"]
for fruit in fruits {
    print("我喜欢吃\(fruit)")
}

字典遍历注意顺序

swift 复制代码
let legCount = ["ant": 6, "snake": 0, "cat": 4]
// 字典无序!同一台机器多次运行顺序都可能不同
for (animal, legs) in legCount {
    print("\(animal) 有 \(legs) 条腿")
}

区间与"忽略值"

swift 复制代码
// 闭区间 ...  包含两端
for i in 1...5 {
    print("5 x \(i) = \(5 * i)")
}

// 半开区间 ..<  忽略最后一项
let minutes = 0..<60          // 0~59
for tick in minutes where tick % 5 == 0 {
    // 只打印 0/5/10/.../55
    print("表盘刻度 \(tick)")
}

// 如果根本不想用下标,用 _ 占位
var base = 1
for _ in 1...10 {            // 3 的 10 次方
    base *= 3
}
print("3^10 = \(base)")     // 59049

stride 灵活跳步

swift 复制代码
// 开区间 stride(from:to:by:)
for degree in stride(from: 0, to: 360, by: 30) {
    print("旋转 \(degree)°")
}

// 闭区间 stride(from:through:by:)
for rate in stride(from: 0.5, through: 1.5, by: 0.25) {
    print("汇率 \(rate)")
}

While 与 Repeat-While:何时选谁?

场景 推荐
可能一次都不执行 while
至少执行一次 repeat-while

蛇梯棋:同一逻辑两种写法

swift 复制代码
let finalSquare = 25
var board = Array(repeating: 0, count: finalSquare + 1)
// 梯子
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
// 蛇
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08

// ----- while 版 -----
var square = 0, diceRoll = 0
while square < finalSquare {
    diceRoll += 1
    if diceRoll == 7 { diceRoll = 1 }          // 模拟 1~6 骰子
    square += diceRoll
    if square < board.count { square += board[square] }
}
print("while 版到达终点")

// ----- repeat-while 版 -----
square = 0; diceRoll = 0
repeat {
    square += board[square]   // 先结算梯子/蛇
    diceRoll += 1
    if diceRoll == 7 { diceRoll = 1 }
    square += diceRoll
} while square < finalSquare
print("repeat-while 版到达终点")

经验:

  • 必须先"爬梯子/滑蛇"再"掷骰子"时,用 repeat-while 可以省一次越界检查。
  • 其余情况 while 可读性更高。

条件语句:if / guard / switch 全维度对比

if 表达式(Swift 5.9+)

swift 复制代码
let temp = 26
// 一行赋值,不再需要三目嵌套
let advice = if temp <= 0 { "穿羽绒服" }
             else if temp >= 30 { "短袖+冷饮" }
             else { "正常穿衣" }
print(advice)   // 正常穿衣

注意:

  • 所有分支必须返回同一类型,否则需要显式标注类型。
  • 可以抛错:let level = if temp > 100 { throw TempError.boiling } else { "ok" }

guard:提前退出,减少金字塔

swift 复制代码
func buy(age: Int, stock: Int) {
    guard age >= 18 else {
        print("未成年禁止购买")
        return
    }
    guard stock > 0 else {
        print("库存不足")
        return
    }
    // 以下代码一定是成年人且有库存
    print("购买成功")
}

guard 与 if 的区别:

  1. 必须带 else
  2. else 内必须中断控制流(return/break/continue/throw/fatalError);
  3. 解绑变量作用域延续到后续代码,避免多层嵌套。

switch:模式匹配大杀器

区间 & 复合值

swift 复制代码
let score = 87
switch score {
case 90...100: print("优秀")
case 80..<90:  print("良好")
case 60..<80:  print("及格")
default:       print("不及格")
}

tuple + where 条件

swift 复制代码
let point = (2, 2)
switch point {
case (0, 0):                  print("原点")
case (let x, 0):              print("在 x 轴,x=\(x)")
case (0, let y):              print("在 y 轴,y=\(y)")
case (let x, let y) where x == y:  print("在对角线 x=y 上")
default:                      print("其他")
}

值绑定与复合 case

swift 复制代码
// 复合 case 共享同一段代码
switch "e" {
case "a", "e", "i", "o", "u": print("小写元音")
case "b", "c", "d", "f", "g": print("部分辅音")
default: print("其他字符")
}

// 复合 case 也支持绑定,但要保证类型一致
switch (2, 0) {
case (let d, 0), (0, let d):   // 两个 pattern 都绑定 d 且类型一致
    print("到轴距离为 \(d)")
default:
    break
}

贯穿:显式 fallthrough

swift 复制代码
let integerToDescribe = 5
var description = "数字 \(integerToDescribe) 是"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
    description += " 质数,且"
    fallthrough          // 继续执行下一个 case
default:
    description += " 是整数。"
}
print(description)   // 数字 5 是 质数,且 是整数。

控制转移语句:continue / break / fallthrough / return / throw

continue & break 的最常见误区

swift 复制代码
// 去掉小写元音与空格
let puzzleInput = "great minds think alike"
let vowels: Set<Character> = ["a", "e", "i", "o", "u", " "]
var output = ""
for ch in puzzleInput {
    if vowels.contains(ch) {
        continue          // 立即进入下一轮
    }
    output.append(ch)
}
print(output)   // grtmndsthnklk

带标签的语句:精确跳出血腥嵌套

swift 复制代码
var finalSquare = 25
var square = 0
gameLoop: while true {
    let dice = Int.random(in: 1...6)
    switch square + dice {
    case finalSquare:
        print("刚好到达,游戏胜利")
        break gameLoop      // 跳出 while,不是跳出 switch
    case let n where n > finalSquare:
        print("点数太大,重新掷")
        continue gameLoop   // 继续 while 下一轮
    default:
        square += dice
    }
}

defer:作用域退出时的"扫尾"利器

swift 复制代码
func updateScore() {
    var score = 10
    if Bool.random() {
        score += 5
        defer { print("本次加分已落地,当前分数:\(score)") }  // 1️⃣ 先写后执行
        defer { score -= 100 }                                // 2️⃣ 再写先执行
        print("离开 if 前 score=\(score)")                      // 15
    }
    print("离开函数前 score=\(score)")                          // -85
}
updateScore()

规则小结:

  • 同一作用域多个 defer 以栈顺序执行(先注册后执行)。
  • 无论正常 return、break、continue、throw 都会执行;进程崩溃除外。
  • 典型场景:文件句柄/锁/数据库事务配对释放。

API 可用性检查:让旧系统安心升级

swift 复制代码
if #available(iOS 15, macOS 12, *) {
    // 仅 iOS15+/macOS12+ 能走到这里
    print("iOS15+/macOS12+")
} else {
    // 低版本走兼容方案
    print("iOS15以下或者macOS12以下或者其他系统,比如Linex、visionOS")
}

// guard 写法,提前 return
func useNewAPI() {
    guard #available(macOS 12, *) else { return }
    // 以下代码编译器保证只在 macOS12+ 运行
}

总结

控制流元素 关键记忆点
for-in 可遍历任何 Sequence;字典无序;stride 可跳步
while vs repeat-while 是否"先检查"
if 表达式 同类型、可抛错、可函数返回值
guard 必须 else 中断,解绑变量作用域外可用
switch exhaustive、默认不贯穿、支持 tuple/where/值绑定
defer 栈式延迟,资源清理黄金搭档
#available 编译期+运行期双重保险

扩展思考:把知识迁移到日常开发

  1. 日志场景

    defer 在函数出口统一打印耗时,避免早期 return 漏埋点。

  2. 资源池

    文件句柄获取后立刻写 defer { fclose(fp) },再也不怕忘记关文件。

  3. 交互式 UI

    利用 stride(from: 0, to: 360, by: 30) 生成圆形按钮坐标,一行代码搞定数学。

  4. 数据校验

    多层 guard 提前返回,把"非法输入"挡在门外,主流程保持一级缩进。

控制流不是"写得出",而是"写得对、写得优雅"。

相关推荐
HarderCoder5 小时前
Swift 控制流深度解析(二):模式匹配、并发与真实项目套路
swift
QWQ___qwq1 天前
SwiftUI 的状态管理包装器(Property Wrapper)
ios·swiftui·swift
大熊猫侯佩2 天前
AI 开发回魂夜:捉鬼大师阿星的 Foundation Models 流式秘籍
llm·ai编程·swift
JZXStudio3 天前
4.布局系统
框架·swift·app开发
HarderCoder3 天前
Swift 函数完全指南(四):从 `@escaping` 到 `async/await`——打通“回调→异步→并发”任督二脉
swift
HarderCoder3 天前
Swift 函数完全指南(三):`@autoclosure`、`rethrows`、`@escaping` 与内存管理
swift
HarderCoder3 天前
Swift 函数完全指南(二):泛型函数与可变参数、函数重载、递归、以及函数式编程思想
swift
HarderCoder3 天前
Swift 函数完全指南(一)——从入门到嵌套
swift