2016-10-10 24 views
1

從Java背景來看,我一直在嘗試自學Scala一段時間。作爲其中的一部分,我正在做一個小型寵物項目,公開一個HTTP端點,將一輛車的registration numberowner對接並返回狀態。從Scala未來完成中返回價值

爲了給出更多的上下文,我使用Slick作爲FRM,它異步執行數據庫操作並返回Future。 根據這個Future的輸出,我想設置status變量返回給客戶端。

這裏,是代碼

def addVehicleOwner(vehicle: Vehicle): String = { 
    var status = "" 
    val addFuture = db.run((vehicles returning vehicles.map(_.id)) += vehicle) 
    addFuture onComplete { 
     case Success(id) => { 
     BotLogger.info(LOGTAG, s"Vehicle registered at $id ") 
     status = String.format("Registration number - '%s' mapped to owner '%s' successfully", vehicle.registration, 
      vehicle.owner) 
     println(s"status inside success $status") //--------- (1) 
     } 
     case Failure(e: SQLException) if e.getMessage.contains("SQLITE_CONSTRAINT") => { 
     status = updateVehicleOwner(vehicle) 
     BotLogger.info(LOGTAG, s"Updated owner='${vehicle.owner}' for '${vehicle.registration}'") 
     } 
     case Failure(e) => { 
     BotLogger.error(LOGTAG, e) 
     status = "Sorry, unable to add now!" 
     } 
    } 
    exec(addFuture) 
    println(s"Status=$status") //--------- (2) 
    status 
    } 

    // Helper method for running a query in this example file: 
    def exec[T](sqlFuture: Future[T]):T = Await.result(sqlFuture, 1 seconds) 

這是在Java中相當簡單。使用Scala時,我面臨以下問題:

  • 預期值在(1)處打印,但(2)總是打印空字符串,並且方法返回的是相同的。有人能解釋爲什麼嗎?
  • 我甚至試圖將var status標記爲@volatile var status,它仍然評估爲空字符串。

  • 我知道,以上並不是我在靜音狀態下做事的功能方式。爲這種情況編寫代碼的乾淨方式是什麼?

  • 幾乎所有我能找到的例子都描述瞭如何映射Success的結果或者通過執行println來處理Failure。我想做的比這更多。
  • 什麼是我可以參考的小項目的一些很好的參考?特別是,遵循TDD。
+0

首先要注意的是,您正在等待addFuture,但它是通過'onComplete'創建的實際上會改變'status'的未來。這可能是您的println沒有達到您的期望的原因。但是,由於各種文檔中提到的所有原因,如果您發現自己在測試之外使用Await.result,您可能錯過了期貨的本質。也許你只是在將來返回狀態值本身(而不是改變外部變量),並且只是通過這個未來,直到有人真正需要結果。 –

回答

4

而不是依靠status瓶蓋內完成的,你可以在recover如果發生該處理異常,始終Future[T]返回你想要的結果。這是Scala採取表情的本質優勢:

val addFuture = 
    db.run((vehicles returning vehicles.map(_.id)) += vehicle) 
    .recover { 
     case e: SQLException if e.getMessage.contains("SQLITE_CONSTRAINT") => { 
     val status = updateVehicleOwner(vehicle) 
     BotLogger.info(
      LOGTAG, 
      s"Updated owner='${vehicle.owner}' for '${vehicle.registration}'" 
     ) 
     status 
     } 
     case e => { 
     BotLogger.error(LOGTAG, e) 
     val status = "Sorry, unable to add now!" 
     status 
     } 
    } 

val result: String = exec(addFuture) 
println(s"Status = $result") 
result 

注意Await.result不應該在任何生產環境中使用,因爲它在Future同步塊,而這正是你真正想要的正好相反。如果您已使用Future委託工作,則需要它異步完成。我假設您的exec方法僅用於測試目的。