You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Scala中对列表执行可失败计算并在失败时立即终止?

不使用异常实现halveAll的方案

Scala 2.x标准库实现

1. 递归模式匹配(直观易懂)

递归是最直接的实现方式,通过模式匹配遍历列表,遇到失败立即返回错误:

def halve(n: Int): Either[String, Int] =
  if (n % 2 == 0) Right(n / 2)
  else Left("cannot halve odd number")

def halveAll(ns: List[Int]): Either[String, List[Int]] = ns match {
  case Nil => Right(Nil)
  case head :: tail =>
    halve(head).flatMap(halvedHead => halveAll(tail).map(halvedHead :: _))
}

原理:

  • 空列表直接返回Right(Nil)
  • 非空列表先处理头元素:若halve(head)失败,直接返回Left终止递归;若成功,递归处理剩余列表,再将结果拼接。

2. foldLeft累积结果

用foldLeft从左到右累积结果,通过flatMap确保一旦出现错误就停止后续处理:

def halveAll(ns: List[Int]): Either[String, List[Int]] =
  ns.foldLeft(Right(Nil): Either[String, List[Int]]) { (acc, n) =>
    acc.flatMap(halvedList => halve(n).map(_ :: halvedList))
  }.map(_.reverse)

原理:

  • 初始累积值为Right(Nil)
  • 每次处理元素时,若当前累积值是Left,flatMap会直接返回该错误,跳过后续元素;若为Right,则调用halve并将结果加入列表
  • 最后反转列表(因为foldLeft会将新元素加到列表头部)

3. Scala 2.13+ 标准库traverse方法

Scala 2.13开始,标准库为集合提供了traverse方法,专门处理这种"遍历+失败即停"的场景:

import scala.util.Either

def halveAll(ns: List[Int]): Either[String, List[Int]] =
  ns.traverse(halve)

这是最简洁的标准库实现,traverse会自动遍历列表,对每个元素应用halve,一旦遇到Left就立即返回,否则收集所有Right的结果。

Cats库优雅实现

Cats的Traverse类型类提供了更通用的解决方案,支持所有实现了Traverse的集合(如List、Vector、Option等):

import cats.Traverse
import cats.implicits._

def halveAll[F[_]: Traverse](ns: F[Int]): Either[String, F[Int]] =
  ns.traverse(halve)

原理:Cats通过类型类抽象了遍历逻辑,traverse方法会利用Either的Applicative实例,实现失败即停的效果,同时保持代码的通用性。

原实现的问题说明

你之前的实现依赖捕获MatchError,存在两个明显问题:

  1. 错误信息被硬编码为"cannot match an odd number",丢失了halve返回的原始错误信息
  2. 异常处理属于副作用,不符合函数式编程的纯函数原则

示例验证

val allEven = List(2, 4, 6, 8)
val evenAndOdd = List(2, 4, 6, 7, 8)

println(halveAll(allEven))    // Right(List(1, 2, 3, 4))
println(halveAll(evenAndOdd)) // Left("cannot halve odd number")

(注:你提供的示例输出写的是原列表,这是因为原代码中yield n而非yield halved,上述实现返回的是减半后的结果,符合halve函数的语义)

内容的提问来源于stack exchange,提问作者Tim Stewart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 14:36:53