这既简洁又正确,但几乎每个读者都会有 难以恢复作者的原意。一个 通常用于澄清的策略是命名中间结果 和参数:
val votesByLang = votes groupBy { case (lang, _) => lang }
val sumByLang = votesByLang map { case (lang, counts) =>
val countsOnly = counts map { case (_, count) => count }
(lang, countsOnly.sum)
}
val orderedVotes = sumByLang.toSeq
.sortBy { case (_, count) => count }
.reverse
如果我在评估votesByLang
,sumByLang
的值时遇到错误,那么我无法理解的是...我怎样才能在最后得到一个recover
毕竟,如果我只有.map.map ...我最后可以有一个recover
。那么这种风格也可以单一恢复吗? (而且不仅可能,而且风格很好......)
或者换句话说,在这个简洁而正确的功能流水线代码中,什么是简洁和正确的错误处理?
你看到非简洁版我能够编写代码:
object MyRealMainObj extends App {
println(
Try(1)
.map(doOne)
.map(doTwo)
.recover { // non succinct version can catch any prior error how to achieve the same in succinct version
case e: Throwable => println("recovering from: " + e.getMessage)
}
)
def doOne(i: Int): Int = { i + 1; throw new RuntimeException("failed in one") }
def doTwo(i: Int): Int = { i + 2; throw new RuntimeException("failed in two") }
}
单个recover
会捕获.map
中的任何先前错误,但简洁明了我怎样才能以简洁明了的方式实现同样的目标呢?
答案 0 :(得分:1)
听起来你期望某种范围被.recover神奇地创造出来。不是这种情况。通过一些小的简化,Try(expr)
是
try {
val result = expr
Success(result)
catch {
e => Failure(e)
}
tryResult.map(f)
是:
tryResult match {
case Success(x) => Try(f(x))
case f: Failure => f
}
tryResult.recover(f)
是
tryResult match {
case Failure(e) if f.isDefinedAt(e) => Try(f(e))
case other => other
}
没有特别的魔力。在每个阶段,您都有值,而不是某些try / catch范围内的代码。将这些值放在val中不会改变事物。如果您"手动调试",您会注意到您获得了一个Success对象,然后在某个时刻,您的某个地图可能会失败并返回一个失败,以下那些将继续失败,然后当你通过最后一个恢复,它可能会回到成功。中间的设置值不会有任何区别。