组合 Either
map 与 flatMap
组合 Either 是 CoddyKit 上的免费 Scala for Backend Engineering & Functional Programming 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Scala for Backend Engineering & Functional Programming 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Scala for Backend Engineering & Functional Programming 课程共包含 4 节课。
组合计算
实际程序会串联多个可能失败的步骤:解析、验证、查找、计算。Either 允许您组合这些步骤,使第一次失败立即终止整个链。
所使用的工具包括 map、flatMap 和 for 推导式。
flatMap 串联 Either
flatMap 会应用一个自身返回 Either 的函数。如果接收者是 Left,则不会调用该函数,而是继续传播这个 Left。
object Main {
def positive(n: Int): Either[String, Int] =
if (n > 0) Right(n) else Left("not positive")
def main(args: Array[String]): Unit = {
val r = Right(5).flatMap(positive)
val l = Right(-1).flatMap(positive)
println(r)
println(l)
}
}短路处理
当您串联多个 flatMap 调用时,第一个 Left 会停止后续所有操作。之后的步骤会被跳过,该错误会成为最终结果。
object Main {
def step(label: String, n: Int): Either[String, Int] = {
println(s"running $label")
Right(n + 1)
}
def main(args: Array[String]): Unit = {
val result = Left("early error").asInstanceOf[Either[String, Int]]
.flatMap(n => step("A", n))
.flatMap(n => step("B", n))
println(result)
}
}对 Either 使用 for 推导式
由于 Either 是右偏的,因此可以在 for 推导式中使用它。每个 <- 都会解包一个 Right;任何 Left 都会停止推导式并成为结果。
object Main {
def parse(s: String): Either[String, Int] =
s.toIntOption.toRight(s"bad: $s")
def main(args: Array[String]): Unit = {
val sum = for {
a <- parse("3")
b <- parse("4")
} yield a + b
println(sum)
}
}失败的 for 推导式
如果推导式中的任何一步产生 Left,整个表达式就是该 Left,后续步骤也不会运行。
object Main {
def parse(s: String): Either[String, Int] =
s.toIntOption.toRight(s"bad: $s")
def main(args: Array[String]): Unit = {
val sum = for {
a <- parse("3")
b <- parse("oops")
c <- parse("5")
} yield a + b + c
println(sum)
}
}串联验证步骤
一个实际的处理流程:先解析字符串,再检查业务规则,最后进行转换。每个阶段都返回一个 Either。
object Main {
def parse(s: String): Either[String, Int] = s.toIntOption.toRight("not a number")
def checkRange(n: Int): Either[String, Int] =
if (n >= 1 && n <= 100) Right(n) else Left("out of range")
def process(s: String): Either[String, Int] =
parse(s).flatMap(checkRange).map(_ * 10)
def main(args: Array[String]): Unit = {
println(process("7"))
println(process("500"))
println(process("x"))
}
}map 与 flatMap
当函数返回普通值时使用 map。当函数返回另一个 Either 时使用 flatMap,以避免嵌套的 Either[String, Either[String, Int]]。
@main def run(): Unit = {
val withMap: Either[String, Int] = Right(2).map(_ + 1)
val nested: Either[String, Either[String, Int]] = Right(2).map(n => Right(n + 1))
val flat: Either[String, Int] = Right(2).flatMap(n => Right(n + 1))
println(withMap)
println(nested)
println(flat)
}组合相互独立的值
即使每一步都不依赖前一步,for 推导式仍然适用。只有所有步骤都成功,最终的 yield 才会执行。
object Main {
def parse(s: String): Either[String, Int] = s.toIntOption.toRight(s"bad: $s")
def main(args: Array[String]): Unit = {
val combined = for {
x <- parse("10")
y <- parse("20")
z <- parse("30")
} yield List(x, y, z).sum
println(combined)
}
}leftMap 风格的错误转换
标准库中的 Either 没有 leftMap,但您可以使用 swap.map(...).swap,或在 fold 内部进行映射来转换错误。这样可以让整个处理流程中的错误类型保持一致。
@main def run(): Unit = {
val e: Either[String, Int] = Left("low-level error")
val mapped = e.swap.map(msg => s"context: $msg").swap
println(mapped)
}综合运用
一个小型计算器处理流程:解析两个数字并执行除法,将所有失败报告为带有类型的错误。
object Main {
def parse(s: String): Either[String, Int] = s.toIntOption.toRight(s"bad number: $s")
def divide(a: Int, b: Int): Either[String, Int] =
if (b == 0) Left("division by zero") else Right(a / b)
def calc(x: String, y: String): Either[String, Int] =
for {
a <- parse(x)
b <- parse(y)
r <- divide(a, b)
} yield r
def main(args: Array[String]): Unit = {
println(calc("20", "4"))
println(calc("20", "0"))
println(calc("x", "4"))
}
}为什么这很重要
组合 Either 可以实现铁路导向编程:正常路径沿着 Right 前进,任何错误都会转入 Left 轨道并绕过其余步骤。不需要异常,不需要空值检查,一切都只是值。
快速检查
检验您对组合 Either 的理解。
回顾
您已经学习了如何组合 Either:
flatMap会串联可能失败的步骤,并在第一个Left处短路。for推导式让多步骤处理流程更易读。- 对普通结果使用
map,对返回 Either 的函数使用flatMap。 - 使用
swap.map(...).swap转换错误。
常见问题解答
「组合 Either」课时是免费的吗?
是的 — 「组合 Either」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Scala for Backend Engineering & Functional Programming 课程的其余内容,请升级到 CoddyKit PRO。 Scala for Backend Engineering & Functional Programming 课程共包含 4 节课。
「组合 Either」这节课中我会学到什么?
map 与 flatMap 你通过在浏览器中直接运行的动手代码来练习 Scala for Backend Engineering & Functional Programming,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Scala for Backend Engineering & Functional Programming 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Scala for Backend Engineering & Functional Programming 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「组合 Either」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Scala for Backend Engineering & Functional Programming 课中编写并运行代码吗?
能。每节 Scala for Backend Engineering & Functional Programming 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。