如何让scala阻止使用tailrec?

时间:2013-08-21 18:48:00

标签: scala java.util.concurrent

我正在写scala< - > Futures的java interop包装器,我不知道实现scala.concurrent.Future.onComplete(http://www.scala-lang.org/api/current/index.html#scala.concurrent.Future)的正确方法。这可能有效:

def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit = {
  executor.execute(new Runnable {
    @tailrec
    def run = value match {
      case Some(t) => func(t)
      case None => { Thread.sleep(100); run }
    }
  })
}

Asynchronous IO in Scala with futures表示当我必须阻止时,我应该将代码的相关部分传递给scala.concurrent.blocking,让ExecutionContext知道是什么。问题是当我用阻塞{}包围值匹配{...}时,它不再是尾调用。

这种众所周知的正确方法是什么?

编辑:为了完整性,这里是整个包装类:

class JavaFutureWrapper[T](val jf: java.util.concurrent.Future[T]) extends scala.concurrent.Future[T] {
  def isCompleted = jf.isDone

  def result(atMost: Duration)(implicit permit: CanAwait): T =
    atMost match { case Duration(timeout, units) => jf.get(timeout, units) }

  def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit = {
    executor.execute(new Runnable {
      @tailrec
      def run = value match {
        case Some(t) => func(t)
        case None => { Thread.sleep(100); run }
      }
    })
  }

  def ready(atMost: Duration)(implicit permit: CanAwait): this.type = atMost match {
    case Duration(timeout, units) => {
      jf.get(timeout, units)
      this
    }
  }

  def value: Option[Try[T]] = (jf.isCancelled, jf.isDone) match {
    case (true, _) => Some(Failure(new Exception("Execution was cancelled!")))
    case (_, true) => Some(Success(jf.get))
    case _ => None
  }
}

2 个答案:

答案 0 :(得分:2)

我只是等待Java未来完成:

import scala.util.{Try, Success, Failure}
import scala.concurrent._
import java.util.concurrent.TimeUnit

class JavaFutureWrapper[T](val jf: java.util.concurrent.Future[T])
  extends scala.concurrent.Future[T] {
  ...

  def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit =
    executor.execute(new Runnable {
      def run: Unit = {
        val result = Try(blocking(jf.get(Long.MaxValue, TimeUnit.MILLISECONDS)))
        func(result)
      }
    })
  ...
}

答案 1 :(得分:0)

嗯,我对0__的答案的编辑没有得到批准,所以为了未来的读者,这里是我要使用的解决方案(从0 __开始简化)

def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit = {
  executor.execute(new Runnable {
    def run = func(Try( blocking { jf.get } ))
  })
}