Scala Implicit类中不能重载apply方法

时间:2015-05-03 08:51:48

标签: scala apply implicit

我正在使用retryasync

撰写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
  }

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) }

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

感谢。

1 个答案:

答案 0 :(得分:2)

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

此外,此实现不起作用:

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

如果Future失败,则不会调用map的函数,并且await会抛出异常,而async会立即导致失败{ {1}}。因此,通过此实现,该函数实际上不会重试。

您需要以下内容:

Future

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

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

然后你可以拥有

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