首页 / Swift 编程语言教程 / for-in 循环

Swift 编程语言教程

for-in 循环

本教程共 93 篇 · 第 24 篇 · 更新于 2026-08-08 · 约 8 分钟阅读

SwiftSwift 编程语言教程for-in循环遍历集合区间遍历strideSequence

本节目标:能用 for-in 把数组、字典、区间、字符串里的每一项依次取出来处理,并在不需要值时用下划线跳过。

循环就是“把一件事重复做很多遍”。Swift 里最常用的循环是 for-in,它专门用来遍历一个序列——数组的每一项、字典的每一对键值、一串数字、一个字符串里的每个字符,都能交给它。你不用手动管下标和边界,语法本身就把这些琐事包办了。

1-1 遍历数组

最直白的用法:把一个数组交给 for-in,每次循环变量自动指向数组里的一个元素。

let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
    print("你好,\(name)!")
}

这里 name 是循环自动声明的常量,每轮依次等于 "Anna""Alex"……直到数组走完。你不用写下标、不用管数组长度,for-in 自己会把节奏安排好。这种“我只要每一项,不关心位置”的场景,for-in 是最优选。

Note

循环变量 name 在每一轮里都是常量,不能在循环体内给它重新赋值。如果需要改,可以自己在外面声明一个 var,或者在循环里操作别的变量。

1-2 遍历字典

字典遍历时,每一轮拿到的是一个 (key, value) 元组。你可以直接拆成两个常量来用。

let numberOfLegs = ["蜘蛛": 8, "蚂蚁": 6, "猫": 4]
for (animalName, legCount) in numberOfLegs {
    print("\(animalName)\(legCount)条腿")
}

注意字典本身没有顺序,遍历出来的先后不代表你插入的先后。别依赖字典的遍历顺序去做逻辑判断,那是未定义行为。如果你需要按某个顺序处理,先对 keys 排序再遍历。

1-3 遍历数字区间

for-in 也能遍历区间,这在“按次数重复”或“生成序列”时很方便。闭区间 ... 两端都包含,半开区间 ..< 不包含上界。

for index in 1...5 {
    print("\(index) 的 5 倍是 \(index * 5)")
}

index 同样是被自动声明的常量,第一轮是 1,第二轮是 2,直到 5。想从 0 开始数到 59(不含 60),用 0..<minutes 最自然。区间遍历的本质,是 for-in 在背后把区间当成了一个序列来迭代。

1-4 不需要值时用下划线

有时候你只关心“循环跑了多少次”,而不在乎当前的计数值。这时用下划线 _ 代替变量名,明确告诉编译器“这个值我不要”。

let base = 3
let power = 10
var answer = 1
for _ in 1...power {
    answer *= base
}
print("\(base)\(power) 次方是 \(answer)")

这段代码算 3 的 10 次方。每轮其实有个计数值,但用不上,于是用 _ 忽略。好处是编译器不会浪费精力去准备一个你根本不用的变量,代码意图也更清楚:这里只数次数,不读计数。

1-5 用 stride 控制步长

区间默认一次走一步。想跳着走,比如每 5 分钟画一个刻度,用 stride(from:to:by:)(不含终点)或 stride(from:through:by:)(含终点)。

let minuteInterval = 5
for tickMark in stride(from: 0, to: 60, by: minuteInterval) {
    // 每 5 分钟一个刻度:0, 5, 10 ... 55
    print(tickMark)
}

stride 返回一个序列,for-in 照常遍历。它比手动写 index += 5 再判断边界清爽得多,也更适合钟表、坐标轴这类有固定间隔的场景。闭区间版本换成 through: 就能把终点也包含进去。

1-6 遍历字符串

字符串也能遍历,每轮拿到一个 Character(字符)。中文、emoji 这类由多个 Unicode 标量组成的字符,会被当作一个整体。

for character in "你好" {
    print(character)
}

这里会依次打印“你”和“好”。如果你更想要字符的个数或逐个处理文本,for-in 是最直接的入口。注意 Swift 的字符是“扩展字形簇”,一个 emoji 算一个字符,这和某些按字节计数的语言不同。

Tip

for-in 并非只能遍历这几样内置类型。只要一个类型遵循了 Sequence 协议,就能被 for-in 遍历。你以后自定义的很多集合类型也能直接用同样的语法,这正是 Swift 协议设计的妙处。

1-7 初学者容易混淆的点

第一,for index in 1...5 里的 index 是常量,别写成 for var index 去指望它可变,需要改就自己在循环外声明变量。

第二,遍历字典拿到的是元组,想分别用 key、value 就写成 for (k, v) in dict,只想要 key 就 for k in dict.keys,只想要 value 就 for v in dict.values

第三,下划线 _ 只是“忽略当前值”,循环该跑几轮还是几轮,它不影响循环次数。别以为写了 _ 循环就会少跑。

1-8 遍历时别改集合本身

一个常见错误:在 for-in 遍历数组的同时,往数组里增删元素。比如一边遍历一边 remove,会导致下标错乱、甚至漏处理或崩溃。Swift 对“在遍历中修改被遍历的集合”很敏感,很多时候会直接运行时报错。

正确做法是:要么先收集要处理的下标,遍历完再改;要么用函数式的 filtermap 产生新集合,而不是在遍历中原地改。把“读”和“写”分开,能避开一大类隐蔽 bug。

1-9 清楚背后发生了什么

for-in 之所以能遍历各种类型,是因为它们在底层遵循了 Sequence 协议,提供了一个叫迭代器(iterator)的东西,每轮从中取下一个元素,取完就结束。你写 for x in collection,等价于向迭代器反复要下一个值。

理解这点后,你就明白为什么 for-in 既安全又清晰:它把“怎么取下一个”的细节藏起来了,你只管对每个元素做什么。当你自己写集合类型时,只要让它遵循 Sequence,同样的 for-in 语法立刻能用上。

掌握 for-in 后,大部分“对一批数据做同样处理”的需求都能优雅解决。下一章看 whilerepeat-while,它们适合“跑多久未知、靠条件判断收尾”的场景,是 for-in 之外另一类重要循环。

1-10 for-in 与集合高阶方法的关系

你以后会学到 mapfilterforEach 这类集合方法,它们本质上也是“对集合每一项做点事”,和 for-in 有重叠。粗略分工:for-in 适合“边遍历边做有副作用的事”(打印、累加、改外部变量);map/filter 适合“纯变换、产出新集合”,不改原数据。

初学时不用纠结选哪个,用 for-in 把逻辑写清楚永远是稳妥起点。等你熟悉函数式写法,再把合适的循环改成 map/filter,代码会更短。但别为了“显得高级”硬套高阶方法——可读性第一。

记一句口诀:for-in 管”有什么”,while 管”到哪停”。当你手里已经有一个数组、字典、区间或字符串,想对里面每一项做点事,for-in 几乎总是默认选择;当你连要处理的东西都还没聚成一个集合、只是按某个条件反复做事,那才轮到 while 出场。分清楚这一点,循环选型就不再纠结。