无法重载 Scala Implicit 中的 apply 方法 class

Can't overload apply method in Scala Implicit class

我正在用 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
  }

Scala 编译器报错。由于 Try 没有应用方法需要 Future[T]。所以我使用 implicit 类

解决了它
  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) }

我的问题是,
为什么我不能使用名称 apply 而不是 convertTriedFuture?似乎 scala 编译器不允许 overload 只允许 implicit 类 中的 apply 方法。

谢谢。

Scala 开始寻找隐式转换,只有当它找不到具有所需签名的现有方法时才会这样做。但是在 Try 伴随对象中已经有一个合适的方法:def apply[T](r: ⇒ T): Try[T],因此 Scala 将 apply 中的 T 推断为 Future[Something] 并且不检查隐式转换.

此外,此实现将不起作用:

def convertTriedFuture[T](f: => Future[T]): Future[Try[T]] = 
  f.map(value => Try(value))

如果 Future 失败,则不会调用 map 的函数,并且会从 await 抛出异常,并且 async 会立即导致失败 Future。所以在这个实现中,函数实际上并没有重试。

你需要这样的东西:

def convertTriedFuture[T](f: => Future[T]): Future[Try[T]] =
  f.map(Success.apply).recover { case e => Failure(e) }

此外,我认为,在 Futures 上定义此恢复方法可能更清晰:

implicit class FutureAdditionalOps[T](f: Future[T]) {
  def recoverError: Future[Try[T]] =
    f.map(Success.apply).recover { case e => Failure(e) }
}

然后你就可以

result = await { block.recoverError }