Scala Implicit类中不能重载apply方法

时间:2022-05-06 20:44:06

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 }