首页 > 解决方案 > 是否有 Scala 模式用于从一系列独立计算中收集错误消息?

问题描述

假设我有一系列需要在最后组合的独立计算:

def makeSauce():  Try[Sauce]  = Success(Sauce("marinara"))
def makeCrust():  Try[Crust]  = Failure(new RuntimeException("stale bread"))
def makeCheese(): Try[Cheese] = Failure(new IllegalArgumentException("moldy cheese"))

for {
  sauce  <- makeSauce()
  crust  <- makeCrust()
  cheese <- makeCheese()
} yield {
  Pizza(sauce, crust, cheese)
}

但是,如果我的任何计算失败,我想要一个描述所有失败的全面错误消息,而不仅仅是第一个。上面的代码没有做我想要的;它只向我展示了第一次失败("stale bread")。相反,它应该抛出一个结合其他两个的超级错误消息,这可能是一系列异常对象、一系列字符串错误消息,甚至只是一个巨大的串联字符串。

或者,可以将其组合成顶级Failure对象,而不是抛出异常:

(for {
  sauce  <- makeSauce()
  crust  <- makeCrust()
  cheese <- makeCheese()
} yield (sauce, crust, cheese)) match {
  case Success((sauce, crust, cheese)) => Pizza(sauce, crust, cheese)
  case Failure(e) => throw e
}

for-comprehension 和Tryhere 仅用于说明;工作解决方案不必使用foror Try。但是,显然上述语法是富有表现力和干净的,几乎可以满足我的要求,因此理想情况下,解决方案会尽可能地坚持下去。

我怎样才能在 Scala 中实现这样的目标?

标签: scalamonadsfor-comprehension

解决方案


验证是您正在寻找的。以猫为例。

import cats.data.Validated
import cats.implicits.catsSyntaxTuple3Semigroupal

def valid(input: String) = if (input.toIntOption.isEmpty) Validated.Invalid(s"$input is not a number")
else Validated.Valid(input.toInt)

def sumThreeNumbers(one:String, two:String, three: String) = (valid(one), valid(two), valid(three)).mapN((oneInt, twoInt, threeInt)=> oneInt + twoInt + threeInt)

sumThreeNumbers("1","2","3")
sumThreeNumbers("1","two","xxx")
//results
val res0: cats.data.Validated[String,Int] = Valid(6)
val res1: cats.data.Validated[String,Int] = Invalid(two is not a number.xxx is not a number.)

 

推荐阅读