如果我有一些验证函数:
def validateOne(a: A): Try[A]
我现在想通过使用 validateOne
函数来验证 A 的集合
def validateAll(all: List[A]): Try[List[A]]
有没有一种很好的方法可以在发现第一个元素无效时立即返回 Failure
?
我现在的做法是在验证每个元素后调用 get
。对于 validateOne
返回 Failure
的第一个元素,get
抛出包装的异常...我捕捉到重新包装:
def validateAll(all: List[A]): Try[List[A]] = try {
all.map(a => validateOne(a).get)
} catch {
case e: MyValidationException => Failure(e)
}
您可以使用 Future.sequence 轻松地将 List[Future[A]]
转换为 Future[List[A]]
.不幸的是,标准库没有为 Try
提供类似的方法。
但是您可以创建自己的尾递归、快速失败函数来迭代结果:
def validateAll[A](all: List[A]): Try[List[A]] = {
//additional param acc(accumulator) is to allow function to be tail-recursive
@tailrec
def go(all: List[A], acc: List[A]): Try[List[A]] =
all match {
case x :: xs =>
validateOne(x) match {
case Success(a) => go(xs, a :: acc)
case Failure(t) => Failure(t)
}
case Nil => Success(acc)
}
go(all, Nil)
}
如果您使用 cats在您的堆栈中,您还可以使用遍历(遍历是 map + sequence):
import cats.implicits._
def validateAll2[A](all: List[A]): Try[List[A]] = all.traverse(validateOne)