我想调整这个example:
def retry[T](f: => Future[T], delays: Seq[FiniteDuration])(implicit ec: ExecutionContext, s: Scheduler): Future[T] = {
f recoverWith { case _ if delays.nonEmpty => after(delays.head, s)(retry(f, delays.tail) }
}
支持以下呼叫:myFuture.retry(Seq(1.seconds, 5.seconds, 10.seconds)).map {data => process(data)}
。
以下是我实施它的方式:
import akka.pattern.after
import akka.actor.Scheduler
import scala.concurrent.{ExecutionContext, Future}
import scala.concurrent.duration.FiniteDuration
object FutureExtension {
implicit class FutureExtension[T](f: Future[T]) {
def retry(delays: Seq[FiniteDuration])(implicit ec: ExecutionContext, s: Scheduler): Future[T] = {
f recoverWith { case _ if delays.nonEmpty => after(delays.head, s)(f.retry(delays.tail)) }
}
}
}
我注意到retry
方法被正确调用,但它没有评估原始未来。在调试时,我注意到未来的值是Failure
,我想这表明我永远无法正常恢复,这意味着我永远不会称之为原始未来。
我该如何解决这个问题?
答案 0 :(得分:3)
这里的关键点是,Future
是按值调用的,而示例Future
是按名称调用的,{{1}表示在它的类型之前。
在调用函数之前,将按值调用参数(scala default)计算一次,然后将其视为=>
。
在函数调用之前不会对按名称调用的参数(使用val
类型定义)进行求值,而是将其作为" thunk",它将在每次执行时执行在函数内部调用。这与=> T
。
事实证明,您可以使用call-by-name参数创建一个隐式类,因此您只需在类参数中添加双箭头def
即可获得所需内容。