在Scala中扩展未来[T]特性有困难
请原谅我对Scala不太了解。我只是一个Java开发人员,希望在Play框架中实现一些功能。我甚至试图用Java代码实现一个trait,但我得到了更模糊的错误。我有以下Scala代码:在Scala中扩展未来[T]特性有困难,scala,playframework-2.0,Scala,Playframework 2.0,请原谅我对Scala不太了解。我只是一个Java开发人员,希望在Play框架中实现一些功能。我甚至试图用Java代码实现一个trait,但我得到了更模糊的错误。我有以下Scala代码: package models import scala.concurrent.Future class SettableFuture[T](name: String) extends Future[T] { var assignedValue: T def set(newValue: 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
暂时忽略这些方法的返回值,它们毫无意义,因为我只是试图修复所有编译错误
在扩展trait时,我只是从编译时异常复制了方法存根,而没有覆盖它的抽象方法,并将它们粘贴到源文件中。我不明白为什么我还是会出错。我查看了waitiable中ready()的签名,看起来返回类型实际上应该是类
编辑:我之所以要实现这一点,是因为在Promise/Future Scala API中,我只能找到让我异步执行长时间运行的阻塞任务的东西。我所追求的是让请求的执行暂停,直到感兴趣的东西在SettableFuture实例中设置了一个值,这就完成了发送响应的承诺。这样,它有点像一个延续。总之,以下是我最终得到的工作代码:
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))
}
}
就您得到的特定错误而言,您正在重写的
ready
方法的返回类型为Awaitable。this.type
-即Awaitable的此实例的特定类型(超级类型的Future
,因此在Future
中,此方法被视为具有返回类型Future.this.type
)。对于SettableFuture
类,这意味着ready
方法的返回类型必须是models.SettableFuture.this.type
您可能会遇到的其他小问题:onComplete
方法的实现应该是{}
,而不是null
,因为后者是类型null的返回。类型,而不是Unit
,var赋值
需要在非抽象类中初始化,这可以通过将=\ucode>添加到定义变量的行中来完成(尽管您确实希望使其至少受到保护
,并提供一个访问器,该访问器将检查它是否已设置-可能通过将变量更改为选项[T]
初始化为None
,或者维护可在访问器中检查的布尔
标志,并通过set
方法将其设置为true
)
然而,就您试图实现的目标而言,您可能只想查看scala.concurrent.Promise
,它表示“对未来结果的承诺”。它有一个方法future
,返回一个future
,以及各种complete
、completeWith
,以及类似的方法,可用于设置承诺的值,这反过来将导致相关的future
变得就绪/完成。可设置的future
类unne成功地混合了未来
和承诺
特征旨在分离的两个关注点:
- 异步提供值(
Promise
),以及
- 等待并对该条款作出反应(
未来
)
与其将未来的视为异步、长时间运行的阻塞计算,不如将其简单地视为未来某个时间可能提供的值。您可以通过多种方式对该值的提供作出反应,包括注册回调或将其映射到其他值。例如,在Play one wi中ll通常会使用如下模式(在Scala中)暂停对请求的处理:
gimmeAFuture方法返回一个Future
,但是请求处理代码不关心如何计算该值
- 使用
Future立即计算。成功
- 与
Future异步计算。应用
,或
- 通过完成
承诺
作为后者的示例,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
对象的引用,因为它只关心该对象的值将被计算(即,承诺的未来)。在找到这个问题后,我重新审视了这个问题,并意识到为什么会有这么多困惑
我计划使用SettableFuture类,因为我在Play Java API中找不到任何类似的类。我想要与.NET中的TaskCompletionSource等效的东西,Aaron的回答清楚地表明Scala正好满足了我的需要。不幸的是,我在Play的Java API中找不到等效的东西
这个链接清楚地解释了为什么我在本应如此简单的事情上遇到如此多的困难。谢谢大家回答我的问题!谢谢你们的帮助。我现在已经完全可以使用Scala代码了。至于承诺和未来的部分,我不确定这是否正是我想要实现的。我感觉像大多数API deals处理长时间运行的阻塞任务。我要做的是让请求的执行暂停,直到感兴趣的东西在SettableFuture实例中设置了一个值,这就完成了发送响应的承诺。这样,它有点像一个延续。您知道Scala库中存在的任何可以像这样的东西?@KevinJin这正是承诺的目的。设置值的代码包含对
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
}