使用 if 筛选
推导式中的守卫
使用 if 筛选 是 CoddyKit 上的免费 Scala for Backend Engineering & Functional Programming 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Scala for Backend Engineering & Functional Programming 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Scala for Backend Engineering & Functional Programming 课程共包含 4 节课。
for 推导式中的守卫
您可以在 for 推导式中添加一个称为守卫的 if 条件。它只保留满足条件的元素,就像 filter 一样。
object Main {
def main(args: Array[String]): Unit = {
val evens = for (x <- 1 to 10 if x % 2 == 0) yield x
println(evens)
}
}守卫会展开为 withFilter
守卫 if cond 会被改写为对 withFilter 的调用(这是 filter 的惰性变体)。
for (x <- xs if p(x)) yield x- 会变成
xs.withFilter(p).map(x => x)
object Main {
def main(args: Array[String]): Unit = {
val sugar = for (x <- List(1, 2, 3, 4) if x > 2) yield x
val desugared = List(1, 2, 3, 4).withFilter(_ > 2).map(x => x)
println(sugar == desugared)
}
}为什么使用 withFilter 而不是 filter
withFilter 是惰性的:它不会创建中间集合。条件只有在后续的 map 或 flatMap 运行时才会应用,从而节省内存和计算量。
object Main {
def main(args: Array[String]): Unit = {
val nums = List(1, 2, 3, 4, 5, 6)
val result = for (n <- nums if n % 3 == 0) yield n * 100
println(result)
}
}多个守卫
您可以串联多个守卫。它们的组合方式类似逻辑 AND:元素必须满足所有条件才能保留下来。
object Main {
def main(args: Array[String]): Unit = {
val result = for {
x <- 1 to 20
if x % 2 == 0
if x % 3 == 0
} yield x
println(result)
}
}带多个生成器的守卫
守卫可以出现在任意生成器之后,用于过滤该层迭代的值。请将守卫紧跟在它所检查的值所属的生成器之后。
object Main {
def main(args: Array[String]): Unit = {
val coprimeSums = for {
x <- 1 to 3
y <- 1 to 3
if x != y
} yield (x, y)
println(coprimeSums)
}
}组合守卫和值绑定
您可以自由地将守卫(if)与值绑定(=)混合使用。顺序很重要:在守卫之前定义的绑定可以在该守卫中使用。
object Main {
def main(args: Array[String]): Unit = {
val result = for {
x <- 1 to 6
square = x * x
if square > 10
} yield square
println(result)
}
}对 String 集合使用守卫
守卫适用于任何谓词,而不只是数值谓词。这里我们根据单词长度进行过滤。
object Main {
def main(args: Array[String]): Unit = {
val words = List("scala", "go", "java", "rust", "c")
val longWords = for (w <- words if w.length >= 4) yield w.toUpperCase
println(longWords)
}
}过滤 Options
对于 Option,不满足条件的守卫会将结果变为 None。这使得 for 推导式成为验证可选值的简洁方式。
object Main {
def main(args: Array[String]): Unit = {
val ok = for (x <- Some(8) if x > 5) yield x
val bad = for (x <- Some(3) if x > 5) yield x
println(ok)
println(bad)
}
}守卫的位置会改变含义
守卫只能看到在它上方绑定的值。将守卫放在它所需的生成器之前将无法编译。请始终将守卫放在相关生成器之后。
object Main {
def main(args: Array[String]): Unit = {
val result = for {
x <- 1 to 3
y <- 1 to 3
if x + y == 4
} yield s"$x + $y = ${x + y}"
result.foreach(println)
}
}守卫与最终过滤
您可以在推导式之后过滤结果,但守卫会在迭代过程中进行过滤。当有多个生成器时,守卫可以及早剪枝,减少总的工作量。
object Main {
def main(args: Array[String]): Unit = {
val withGuard = for {
x <- 1 to 100
if x % 25 == 0
} yield x
println(withGuard)
}
}易读的验证流程
将多个守卫叠加起来,就像一份条件检查清单。这是实际 Scala 代码中使用 for 推导式最符合惯用风格的方式之一。
object Main {
def main(args: Array[String]): Unit = {
val valid = for {
n <- List(4, 7, 12, 15, 20)
if n > 5
if n < 18
if n % 2 == 0
} yield n
println(valid)
}
}快速检查
for 推导式中的守卫(if)会被脱糖为哪个方法?
回顾
您学习了 for 推导式中的守卫:
if cond会在迭代过程中过滤元素- 守卫会脱糖为
withFilter(惰性过滤) - 多个守卫的组合方式类似逻辑 AND
- 守卫只能看到在它上方绑定的值
- 守卫可以与生成器和
=绑定自由组合
常见问题解答
「使用 if 筛选」课时是免费的吗?
是的 — 「使用 if 筛选」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Scala for Backend Engineering & Functional Programming 课程的其余内容,请升级到 CoddyKit PRO。 Scala for Backend Engineering & Functional Programming 课程共包含 4 节课。
「使用 if 筛选」这节课中我会学到什么?
推导式中的守卫 你通过在浏览器中直接运行的动手代码来练习 Scala for Backend Engineering & Functional Programming,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Scala for Backend Engineering & Functional Programming 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Scala for Backend Engineering & Functional Programming 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「使用 if 筛选」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Scala for Backend Engineering & Functional Programming 课中编写并运行代码吗?
能。每节 Scala for Backend Engineering & Functional Programming 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。