2013-11-01 27 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中找不到相同的內容。

這個鏈接清楚地說明了爲什麼我在應該如此簡單的事情上遇到了這麼大的困難。感謝所有回答我的問題!