2013-11-01 28 views
0

请原谅我对Scala的不理解。我只是一个想要在Play框架中工作的Java开发人员。我甚至试图使用Java代码来实现一个特性,但是我得到了更加晦涩的错误。我有以下Scala代码:故障扩展Scala的未来[T]特性

package models 

import scala.concurrent.Future 

class SettableFuture[T](name: String) extends Future[T] { 
    var assignedValue: T 

    def set(newValue: T) = 
     assignedValue = newValue 

    //override abstract methods in Future[T] 
    def ready(atMost: scala.concurrent.duration.Duration)(implicit permit: scala.concurrent.CanAwait): models.SettableFuture[T] = 
     this 

    def result(atMost: scala.concurrent.duration.Duration)(implicit permit: scala.concurrent.CanAwait): T = 
     assignedValue 

    def isCompleted: Boolean = 
     false 

    def onComplete[U](func: scala.util.Try[T] => U)(implicit executor: scala.concurrent.ExecutionContext): Unit = 
     null 

    def value: Option[scala.util.Try[T]] = 
     null 
} 

这是我的错误:

overriding method ready in trait Awaitable of type (atMost: scala.concurrent.duration.Duration)(implicit permit: scala.concurrent.CanAwait)SettableFuture.this.type; method ready has incompatible type 

忽略的,现在的方法的返回值,他们是荒谬的,因为我只是试图解决所有编译错误。

我简单地从扩展特性时编译时异常中复制了方法存根,而不覆盖其抽象方法并将它们粘贴到我的源文件中。我不明白为什么我仍然有错误。我在Awaitable看了ready()的签名,看起来返回类型实际上应该是类。

编辑:为什么我要实现这个原因是因为在Promise/Future Scala API中,我只能找到让我异步执行长时间运行的阻塞任务的东西。我所追求的是一些可以暂停请求的执行,直到感兴趣的东西在SettableFuture实例中设置一个值,从而完成发送响应的Promise。这样就有点像延续了。总之,这里是我结束了工作代码:

package models 

import java.util.concurrent.CountDownLatch 
import java.util.concurrent.TimeUnit 
import java.util.concurrent.atomic.AtomicInteger 

import scala.concurrent.CanAwait 
import scala.concurrent.ExecutionContext 
import scala.concurrent.Future 
import scala.concurrent.duration.Duration 
import scala.util.Try 

class SettableFuture[T]() extends Future[T] { 
    private final val ValueNotSet = 0 
    private final val ValueBeingSet = 1 
    private final val ValueSet = 2 

    private val valueStatus: AtomicInteger = new AtomicInteger(ValueNotSet) 
    private val onCompleteWaitHandle: CountDownLatch = new CountDownLatch(1) 
    private var onComplete: Try[T] => _ = _ 
    private var assignedValue: T = _ 

    /** Set a value and complete this Future. 
     * 
     * Returns false if the value has already been set by a past call to this method. 
     * Otherwise, marks this Future as complete, executes the function passed to 
     * onComplete, and finally returns true. 
     */ 
    def set(newValue: T): Boolean = { 
     //set value and trigger onComplete only once 
     if (valueStatus.compareAndSet(ValueNotSet, ValueBeingSet)) { 
      assignedValue = newValue 
      valueStatus.set(ValueSet) 
      onCompleteWaitHandle.countDown() 
      if (onComplete != null) 
       onComplete(Try(assignedValue)) 
      true 
     } 
     false 
    } 

    //override abstract methods in the Future[T] trait 
    def ready(atMost: Duration)(implicit permit: CanAwait): this.type = { 
     onCompleteWaitHandle.await(atMost.length, atMost.unit) 
     this 
    } 

    def result(atMost: Duration)(implicit permit: CanAwait): T = { 
     ready(atMost) 
     assignedValue 
    } 

    def isCompleted: Boolean = (valueStatus.get() == ValueSet) 

    def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit = 
     onComplete = func 

    def value: Option[Try[T]] = { 
     if (!isCompleted) 
      None 
     Some(Try(assignedValue)) 
    } 
} 

回答

5

在你所得到的特定错误方面,ready方法要覆盖有Awaitable.this.type返回类型 - 即。该实例的具体类型为Awaitable(超类型Future,因此在Future中,此方法看起来具有返回类型Future.this.type)。对于您的SettableFuture类,这意味着ready方法的返回类型需要为models.SettableFuture.this.type

其他小问题,你可以期望命中:onComplete方法的实现应该是{},不null,因为后者是Null.type类型,而不是Unit的回报,assignedValue需要VAR在非抽象被初始化可以通过将= _添加到定义变量的行来完成(尽管您确实至少要将其设置为protected,并提供一个访问器来检查它是否已被设置 - 可能通过将变量更改为Option[T]初始化为None,否则保持Boolean标志可以在存取器中检查,并且由设置为方法)。

然而,就您试图达到的目标而言,您可能只想查看scala.concurrent.Promise,这代表了“未来结果的承诺”。它有一个方法future返回Future,和各种complete,completeWith,以及可用于设置Promise的值,这反过来将导致相关Future准备好/完成类似的方法。

+0

感谢您的帮助。我现在已经完全使用了Scala代码。至于Promise和Future,我不确定这是否正是我想要实现的。我觉得大部分API都处理长时间运行,阻塞任务。我所追求的是一些可以暂停请求的执行,直到感兴趣的东西在SettableFuture实例中设置一个值,从而完成发送响应的Promise。这样就有点像延续了。您是否知道Scala库中存在的任何类似的东西? –

+1

@KevinJin这就是'Promise'的意思。将设置该值的代码保留对Promise'p'的引用,它将在未来的某个时刻用值完成。等待该值的计算获得对'p.future'的引用,并且可以以通常的方式(注册回调,映射等)对将来的完成作出反应。 –

2

SettableFuture类不必要地混合所述两个关注的是,FuturePromise性状设计成分离:

  • 异步规定的值(Promise)的,和
  • 等待和响应该规定( Future

与其将Future视为异步,长期运行的阻塞计算这可能有助于将其简单地看作是未来可能提供的价值。您可以通过多种方式对提供该值作出反应,包括注册回调或将其映射到其他值。例如,在播放一个往往会暂停请求的处理与这样的图案(Scala中):

def handleRequest = Action { 
    Async { 
    gimmeAFuture().map(value => Ok(value)) 
    } 
} 

def gimmeAFuture(): Future[JsValue] = // ... 

的gimmeAFuture方法返回Future,但请求的处理代码不关心如何值被计算。这可能是

  • Future.successful立即计算,
  • Future.apply异步计算或
  • 通过的Promise

完成供给作为后者的一个例子,gimmeAFuture方法可能实施如下:

def gimmeAFuture: Future[JsValue] = { 
    val p = Promise.apply[JsValue]() 
    // asynchronously complete the promise 30 seconds from now 
    scheduler.scheduleOnce(30.seconds)(p.complete(Success(someJsObject))) 
    // return the future immediately 
    p.future 
} 

当然,您可以实现该方法,但无论您想要什么。关键是需要保留该对象并用值填充以恢复对请求的处理。请求处理程序本身不会获得对Promise对象的引用,因为它只关心将要计算的值(即Promise的未来)。

0

找到这link后我重新回到这个问题,我意识到为什么有这么多的困惑。

我打算使用SettableFuture类,因为我找不到像Play API中已经存在的任何东西。我想要一个与.NET中的TaskCompletionSource等价的东西,而Aaron的回答很清楚,Scala正是我所需要的。不幸的是,我在Play的Java API中找不到相同的内容。

这个链接清楚地说明了为什么我在应该如此简单的事情上遇到了这么大的困难。感谢所有回答我的问题!