使用不同签名的通用回调函数
Posted
技术标签:
【中文标题】使用不同签名的通用回调函数【英文标题】:wrapping around generic callback function with different signatures 【发布时间】:2015-10-18 06:47:49 【问题描述】:我正在尝试学习 Scala,到目前为止,它似乎是一门非常强大的语言,但有些事情似乎很难实现,可能只是我的学习曲线。我在网上研究了几天,但找不到一个很好的解决方案来做我想做的事情。
我有多个方法(具有不同的签名,包括返回类型),我想将它们包含在重试逻辑中。
我想继续调用一个方法预定义的次数,直到方法成功。
这是一个例子:
def downloadLocal(memory: Boolean, userName: Name, version: Int): Int
def downloadRemote(
memory: Boolean, userName: Name, masterNodeId: String, masterNodeId: String
): Pair(Int, Int)
我想将这两个方法包装在重试逻辑中。这是我对重试逻辑的尝试:
trait WithRetry
def withRetry(retry :Int)
try
callBack
catch
case exception:Throwable =>
if(retry>0)
logger.warn(exec+" method failed with an exception. retry number is:" + retry);
logger.warn(exception);
withRetry(retry-1)
else
throw exception
def callBack():Any
我遇到的问题是我无法在重试逻辑中找到一种干净的方法来包装我的方法(downloadRemote
和 downloadLocal
)。
有什么建议/想法吗?
【问题讨论】:
【参考方案1】:你可以定义一个通用函数:
import scala.util.Try, Success, Failure
def retry[T](times: Int)(block: => T): T = Try(block) match
case Success(result) => result
case Failure(e) =>
if (times > 0)
logger.warn(s"method failed with an exception, retry #$times")
logger.warn(exception)
retry(times - 1)(block)
else throw e
这是一个尾递归函数,因此它与在 Java 中的 for 循环中调用该函数一样高效。
然而,更惯用的 Scala 会返回 Try
:
def retry2[T](times: Int)(block: => T): Try[T] =
Try(block) match
case Failure(e) if (times > 0) =>
logger.warn(s"method failed with an exception, retry #$times")
logger.warn(exception)
retry2(times - 1)(block)
case other => other
两个版本都可以用作:
def failRandomly: Int =
if (scala.util.Random.nextInt < 0.80) throw new Exception("boom")
else 1
scala> retry(2)(failRandomly)
res0: Int = 1
scala> retry(2)(failRandomly)
java.lang.Exception: boom // ...
scala> retry2(2)(failRandomly)
res1: scala.util.Try[Int] = Success(1)
scala> retry2(2)(failRandomly)
res2: scala.util.Try[Int] = Failure(java.lang.Exception: boom)
【讨论】:
非常感谢您的回复。使其可移植的建议方法是什么,以便其他方法可以使用它?我可以将它包装在一个类中(如下所示)并使方法静态还是有更好的方法? bold public class RetryUtil def retry[T](times: Int)(block: => T): T = Try(block) match case Success(result) => result case Failure(e ) => if (times > 0) logger.warn(s"method failed with an exception, retry #$retry") logger.warn(exception) retry(times - 1)(block) else throw e 粗体 您可以将它与每个功能一起使用,例如:retry2(5)(downloadLocal(true, "username", 2))
在 Scala 中我们没有静态方法,我们会在对象中创建一个方法。见Difference between object and class in Scala以上是关于使用不同签名的通用回调函数的主要内容,如果未能解决你的问题,请参考以下文章