简体   繁体   English

无法在Scala隐式类中重载apply方法

[英]Can't overload apply method in Scala Implicit class

I am writing a retry function with async and await 我正在使用asyncawait编写retry功能

  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. Scala编译器报告错误。 Since Try doesn't have apply methods takes Future[T] . 由于Try没有应用方法,因此需要使用Future[T] So I solved it using implicit classes 所以我用隐式类解决了

  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 ? 为什么不能使用名称apply而不是convertTriedFuture It seems that the scala compiler doesn't allow overload only about apply methods in implicit classes . 似乎scala编译器不允许仅重载 隐式类中的 apply方法。

Thanks. 谢谢。

Scala starts to look for implicit conversions, only when it can't find an existing method with the required signature. Scala仅在找不到具有所需签名的现有方法时才开始寻找隐式转换。 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. 但是在Try伴随对象中,已经有一个合适的方法: def apply[T](r: ⇒ T): Try[T] ,因此Scala apply T推断为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 . 如果Future失败,则不会调用map的函数,并且从await抛出Exception,并且async立即导致失败的Future So with this implementation the function doesn't actually retry. 因此,使用此实现,该函数实际上不会重试。

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 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM