请原谅我对Scala的不理解。我只是一个想要在Play Framework中工作的Java开发人员。我甚至尝试使用Java代码实现一个特性,但是我得到了更加模糊的错误。我有以下Scala代码:
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))
}
}
答案 0 :(得分:5)
就您所获得的具体错误而言,您覆盖的ready
方法的返回类型为Awaitable.this.type
- 即。此Awaitable
实例的特定类型(Future
的超类型,因此在Future
中,此方法的返回类型为Future.this.type
}。对于SettableFuture
类,这意味着ready
方法的返回类型必须为models.SettableFuture.this.type
。
您可能遇到的其他小问题:onComplete
方法的实现应该是{}
,而不是null
,因为后者是类型Null.type
的返回,而不是Unit
,var assignedValue
需要在非抽象类中初始化,这可以通过将= _
添加到定义变量的行来完成(尽管你真的想要它至少protected
,并提供一个访问器,用于检查是否已设置 - 可能是将变量更改为Option[T]
初始化为None
,或者保留Boolean
可以在访问者中检查的标记,以及true
方法设置为set
的标记。
然而,就您想要实现的目标而言,您可能只想查看scala.concurrent.Promise
,这代表了“未来结果的承诺”。它有一个方法future
,它返回Future
,以及各种complete
,completeWith
和类似的方法,可用于设置Promise
的值,这将导致相关的Future
准备就绪/完成。
答案 1 :(得分:2)
SettableFuture
课程不必要地混淆了Future
和Promise
特征被设计为分开的两个问题:
Promise
)和Future
)不是将Future
视为异步,长时间运行的阻塞计算,而是将其简单地视为可能在将来某个时间提供的值。您可以通过多种方式对该值的提供做出反应,包括注册回调或将其映射到其他值。例如,在Play中,通常会暂停使用这样的模式处理请求(在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
对象的引用,因为它只关心将要计算的值(即Promise的未来)。
答案 2 :(得分:0)
我在找到link之后重新审视了这个问题,我意识到为什么会有这么多混乱。
我打算使用SettableFuture类,因为我找不到Play Java API中已有的类似内容。我想要一些与.NET中的TaskCompletionSource相当的东西,而Aaron的回答清楚地表明Scala正是我所需要的。不幸的是,我在Play的Java API中找不到相同的东西。
这个链接清楚地解释了为什么我对那些应该如此简单的事情感到非常困难。谢谢大家回答我的问题!