I am writing a retry
function with async
and await
我正在使用async和await编写重试函数
def awaitRetry[T](times: Int)(block: => Future[T]): Future[T] = async {
var i = 0
var result: Try[T] = Failure(new RuntimeException("failure"))
while (result.isFailure && i < times) {
result = await { Try(block) } // can't compile
i += 1
}
result.get
}
The Scala compiler reports an error. Since Try
doesn't have apply methods takes Future[T]
. So I solved it using implicit classes
Scala编译器报告错误。由于Try没有应用方法需要Future [T]。所以我用隐式类解决了它
implicit class TryCompanionOps(val t: Try.type) extends AnyVal {
// can't use `apply`!
def convertTriedFuture[T](f: => Future[T]): Future[Try[T]] =
f.map(value => Try(value))
}
// now we can convert Future[T] into Future[Try[T]] e.g,
await { Try.convertTriedFuture(block) }
My question is,
Why can't I use the name apply
instead of convertTriedFuture
? It seems that the scala compiler doesn't allow overload only about apply
methods in implicit classes.
我的问题是,为什么我不能使用apply而不是convertTriedFuture?看起来scala编译器不允许重载只有隐式类中的apply方法。
Thanks.
1 个解决方案
#1
Scala starts to look for implicit conversions, only when it can't find an existing method with the required signature. But in Try
companion object there is already a suitable method: def apply[T](r: ⇒ T): Try[T]
, so Scala infers T
in apply
as Future[Something]
and doesn't check for implicit conversions.
Scala开始寻找隐式转换,只有当它无法找到具有所需签名的现有方法时。但是在Try伴侣对象中已经有了一个合适的方法:def apply [T](r:⇒T):尝试[T],因此Scala推断T in apply as Future [Something]并且不检查隐式转换。
Also, this implementation won't work:
此外,此实现不起作用:
def convertTriedFuture[T](f: => Future[T]): Future[Try[T]] =
f.map(value => Try(value))
If the Future
is failed, map
's function isn't called, and the Exception is thrown from await
, and async
immediately results in a failed Future
. So with this implementation the function doesn't actually retry.
如果Future失败,则不调用map的函数,并且等待抛出异常,async会立即导致失败的Future。因此,通过此实现,该函数实际上不会重试。
You need something like:
你需要这样的东西:
def convertTriedFuture[T](f: => Future[T]): Future[Try[T]] =
f.map(Success.apply).recover { case e => Failure(e) }
Also, I think, it might be cleaner to define this recovery method on Futures:
另外,我认为,在期货上定义这种恢复方法可能更清晰:
implicit class FutureAdditionalOps[T](f: Future[T]) {
def recoverError: Future[Try[T]] =
f.map(Success.apply).recover { case e => Failure(e) }
}
And then you can have
然后你可以拥有
result = await { block.recoverError }
#1
Scala starts to look for implicit conversions, only when it can't find an existing method with the required signature. But in Try
companion object there is already a suitable method: def apply[T](r: ⇒ T): Try[T]
, so Scala infers T
in apply
as Future[Something]
and doesn't check for implicit conversions.
Scala开始寻找隐式转换,只有当它无法找到具有所需签名的现有方法时。但是在Try伴侣对象中已经有了一个合适的方法:def apply [T](r:⇒T):尝试[T],因此Scala推断T in apply as Future [Something]并且不检查隐式转换。
Also, this implementation won't work:
此外,此实现不起作用:
def convertTriedFuture[T](f: => Future[T]): Future[Try[T]] =
f.map(value => Try(value))
If the Future
is failed, map
's function isn't called, and the Exception is thrown from await
, and async
immediately results in a failed Future
. So with this implementation the function doesn't actually retry.
如果Future失败,则不调用map的函数,并且等待抛出异常,async会立即导致失败的Future。因此,通过此实现,该函数实际上不会重试。
You need something like:
你需要这样的东西:
def convertTriedFuture[T](f: => Future[T]): Future[Try[T]] =
f.map(Success.apply).recover { case e => Failure(e) }
Also, I think, it might be cleaner to define this recovery method on Futures:
另外,我认为,在期货上定义这种恢复方法可能更清晰:
implicit class FutureAdditionalOps[T](f: Future[T]) {
def recoverError: Future[Try[T]] =
f.map(Success.apply).recover { case e => Failure(e) }
}
And then you can have
然后你可以拥有
result = await { block.recoverError }