递归 + 一流函数 按名称参数 == 很棒。
def retry[T](n: Int)(fn: => T): T = {
try {
fn
} catch {
case e =>
if (n > 1) retry(n - 1)(fn)
else throw e
}
}
用法是这样的:
retry(3) {
// insert code that may fail here
}
Edit:略有变化的灵感来自@themel https://stackoverflow.com/users/334485/themel的回答。少一行代码:-)
def retry[T](n: Int)(fn: => T): T = {
try {
fn
} catch {
case e if n > 1 =>
retry(n - 1)(fn)
}
}
再次编辑:递归让我感到困扰,因为它添加了对堆栈跟踪的多次调用。由于某种原因,编译器无法优化 catch 处理程序中的尾递归。不过,尾递归不在 catch 处理程序中,优化得很好:-)
@annotation.tailrec
def retry[T](n: Int)(fn: => T): T = {
val r = try { Some(fn) } catch { case e: Exception if n > 1 => None }
r match {
case Some(x) => x
case None => retry(n - 1)(fn)
}
}
再次编辑:显然我会让不断回来并添加这个答案的替代方案成为一种爱好。这是一个尾递归版本,比使用更简单Option
,但是使用return
短路函数并不是 Scala 惯用的做法。
@annotation.tailrec
def retry[T](n: Int)(fn: => T): T = {
try {
return fn
} catch {
case e if n > 1 => // ignore
}
retry(n - 1)(fn)
}
斯卡拉 2.10 更新。由于我的爱好,我偶尔会重新审视这个答案。 Scala 2.10 介绍Try http://www.scala-lang.org/api/current/index.html#scala.util.Try%24,它提供了一种以尾递归方式实现重试的干净方法。
// Returning T, throwing the exception on failure
@annotation.tailrec
def retry[T](n: Int)(fn: => T): T = {
util.Try { fn } match {
case util.Success(x) => x
case _ if n > 1 => retry(n - 1)(fn)
case util.Failure(e) => throw e
}
}
// Returning a Try[T] wrapper
@annotation.tailrec
def retry[T](n: Int)(fn: => T): util.Try[T] = {
util.Try { fn } match {
case util.Failure(_) if n > 1 => retry(n - 1)(fn)
case fn => fn
}
}