一、基础遍历形式
1. 遍历范围(Range)
- 语法:使用
to
(闭区间)或until
(左闭右开区间)。 - 示例:
scala复制代码
// 遍历 1 到 3(包含 3) for (i <- 1 to 3) { println(i) // 输出 1, 2, 3 } // 遍历 1 到 2(不包含 3) for (i <- 1 until 3) { println(i) // 输出 1, 2 }
2. 遍历集合(List/Array/Set等)
- 语法:直接遍历集合中的每个元素。
- 示例:
scala复制代码
val fruits = List("Apple", "Banana", "Orange") for (fruit <- fruits) { println(fruit) // 依次输出每个水果名 }
二、高级遍历形式
1. 多生成器(嵌套循环)
- 语法:多个
<-
生成器,实现嵌套循环(笛卡尔积)。 - 示例:
scala复制代码
val colors = List("Red", "Blue") val sizes = List("S", "L") for { color <- colors size <- sizes } { println(s"$color-$size") // 输出 Red-S, Red-L, Blue-S, Blue-L }
2. 条件过滤(Guard 守卫)
- 语法:用
if
在生成器后添加过滤条件。 - 示例:
scala复制代码
val nums = List(1, 2, 3, 4, 5) for { n <- nums if n % 2 == 0 // 只保留偶数 if n > 2 // 多重条件(等效于 &&) } { println(n) // 输出 4 }
3. 模式匹配解构
- 语法:在生成器中直接解构元组、Case Class 等。
- 示例:
scala复制代码
val pairs = List((1, "A"), (2, "B"), (3, "C")) // 解构元组 for ((num, char) <- pairs) { println(s"$num-$char") // 输出 1-A, 2-B, 3-C }
三、生成新集合(for-yield
)
1. 基础用法
- 语法:
for
后必须加yield
,生成新集合。 - 示例:
scala复制代码
val nums = List(1, 2, 3) val doubled = for (n <- nums) yield n * 2 // List(2, 4, 6)
2. 复杂转换
- 示例:结合多生成器、过滤和模式匹配。
scala复制代码
val pairs = List(("A", 1), ("B", 2), ("C", 3)) val result = for { (char, num) <- pairs // 解构元组 if num > 1 // 过滤条件 suffix <- List("X", "Y") // 嵌套生成器 } yield s"$char$num$suffix" // 结果:List("B2X", "B2Y", "C3X", "C3Y")
四、特殊场景
1. 遍历 Option
类型
- 用途:优雅处理可能为
None
的值。 - 示例:
scala复制代码
val a: Option[Int] = Some(2) val b: Option[Int] = Some(3) val sum = for { x <- a // 若 a 是 None,直接返回 None y <- b } yield x + y // Some(5)
2. 遍历 Map
- 语法:遍历键值对(每个元素是
(K, V)
元组)。 - 示例:
scala复制代码
val map = Map("A" -> 1, "B" -> 2) for ((k, v) <- map) { println(s"Key: $k, Value: $v") }
五、底层原理
Scala 的 for
循环会被编译器转换为 map
、flatMap
和 filter
的组合:
- 单生成器 +
yield
:scala复制代码
for (x <- list) yield f(x) // 等价于 list.map(x => f(x))
- 多生成器 + 过滤:
scala复制代码
for { x <- list1 y <- list2 if cond } yield f(x, y) // 等价于 list1.flatMap(x => list2.filter(y => cond).map(y => f(x, y)))
六、常见错误
忘记
yield
:scala复制代码
// 错误:返回 Unit,不会生成新集合 val result = for (n <- List(1,2)) { n * 2 } // 正确:加 yield val result = for (n <- List(1,2)) yield n * 2
守卫位置错误:
scala复制代码
// 错误:if 必须跟在生成器后 for (n <- List(1,2); if n > 1; m <- List(3,4)) yield m
总结
- 基础:范围遍历、集合遍历。
- 进阶:多生成器、过滤、模式匹配。
- 生成集合:必须用
yield
,类型与输入一致。 - 底层:转换为
map
/flatMap
/filter
,理解性能影响。