我有几个遵循这种模式的代码块:
// Dummy function defs.
def result(i : Int, d : Double, b : Boolean) = {
if (b) d else i
}
def fA(s : String) = {7}
def fB(s : String, i : Int) = {1.0}
def fC(s : String, i : Int, d : Double) = {true}
// Actual code.
def test(s : String) : Double = {
try {
val a = fA(s)
try {
val b = fB(s, a)
try {
val c = fC(s, a, b)
result(a, b, c)
} catch {
case _ => result(a, b, false)
}
} catch {
case _ => result(a, 0.0, false)
}
} catch {
case _ => result(0, 0.0, false)
}
}
Run Code Online (Sandbox Code Playgroud)
其中a,b,&c依次由相应的函数计算,然后将值传递给结果函数.如果在任何阶段发生异常,则使用默认值代替剩余变量.
是否有更惯用的方式来表达此代码.它让我想起Monads,因为它是一系列链式计算,如果任何计算失败,它会立即纾困.
我不确定你是否可以使用monad,因为在每一步你有两个选择(例外或结果)并且忠实于原始代码,除非你不想调用fB或fC函数.
我无法优雅地删除默认值的重复,所以我离开它,因为我认为它更清楚.这是我的非monadic版本基于either.fold和control.Exception:
def test(s : String) = {
import util.control.Exception._
val args =
allCatch.either(fA(s)).fold(err => (0, 0.0, false), a =>
allCatch.either(fB(s, a)).fold(err => (a, 0.0, false), b =>
allCatch.either(fC(s, a, b)).fold(err => (a, b, false), c =>
(a, b, c))))
(result _).tupled(args)
}
Run Code Online (Sandbox Code Playgroud)
这些类型的问题正是Try旨在解决一些更多的问题(比嵌套try/catch块).
Try表示可能导致异常或返回成功计算值的计算.它有两个子类 - Success和Failure.
非常有趣的是,这个问题突然出现了 - 几天前,我完成了一些补充和重构scala.util.Try,对于2.10版本而且这个SO问题有助于说明组合器的一个重要用例,我们最终决定包括; transform.
(截至撰写本文时,transform目前正处于夜间,将于今日或明天发布于2.10-M5之后的Scala.有关详细信息Try和用法示例,请参阅夜间文档)
使用transform(通过嵌套),可以使用Trys 实现,如下所示:
def test(s: String): Double = {
Try(fA(s)).transform(
ea => Success(result(0, 0.0, false)), a => Try(fB(s, a)).transform(
eb => Success(result(a, 0.0, false)), b => Try(fC(s, a, b)).transform(
ec => Success(result(a, b, false)), c => Try(result(a, b, c))
)
)
).get
}
Run Code Online (Sandbox Code Playgroud)