簡體   English   中英

Scala方法/播放框架/其余部分中的檢查錯誤

[英]Inspection error in scala method / play framework / rest

我仍在學習scala,所以這可能是一個簡單的答案,但是我一直在反復寫一個方法長達近一天的時間,無法編譯此代碼。

我正在玩Play框架和反應性mongo模板,以了解Scala和Play的工作方式。 我有一個帶有一些方法的控制器,一個REST服務的端點。

問題與以下方法有關,該方法接受json對象列表並使用mongo反應性驅動程序更新這些對象。 該類具有一個citiesFuture成員,該成員的類型為Future[JSONCollection] 我要添加此方法的原始類代碼可以在上下文中找到: github上的CityController

def updateAll() = Action.async(parse.json) { request =>
  Json.fromJson[List[City]](request.body) match {
    case JsSuccess(givenCities, _) =>
      citiesFuture onComplete[Future[Result]] { cities =>
        val updateFutures: List[Future[UpdateWriteResult]] = for {
          city <- givenCities
        } yield cities.get.update(City.getUniqueQuery(city), Json.obj("$set" -> city))

        val promise: Promise[Result] = Promise[Result] {
          Future.sequence(updateFutures) onComplete[Result] {
            case s@Success(_) =>
              var count = 0
              for {
                updateWriteResult <- s.value
              } yield count += updateWriteResult.n
              promise success Ok(s"Updated $count cities")
            case Failure(_) =>
              promise success InternalServerError("Error updating cities")
          }
        }
        promise.future
      }
    case JsError(errors) =>
      Future.successful(BadRequest("Could not build a city from the json provided. " + Errors.show(errors)))
  }
}

我已經通過大量的嘗試和錯誤努力做到了這一點,但是我開始理解一些scala和Futures的機制是如何工作的,我認為:)我認為我已經接近了,但是我的IDE仍然給了我僅在promise.future行上方的單個右花括號處出現一個檢查錯誤。

該錯誤顯示為: 類型為Unit的表達式不符合預期的Nothing類型 我已經檢查了Promise和onComplete代碼塊的期望返回值,但是我不相信他們期望Nothing作為返回類型。

有人可以向我解釋我所缺少的,而且,我敢肯定,這樣做可以做得更好,所以請告訴我您是否有任何可以借鑒的技巧!

您在正確的軌道上挺好的,但是正如@cchantep所說,一旦您在Future land進行操作,需要使用Promise.future創建自己的Promise.future是非常不尋常的。

另外,看到使用onComplete實際上是很不尋常的-慣用的Scala通常偏向於對Future map的“更高層次”抽象。 我將嘗試演示如何在Play控制器中編寫您的函數:

首先 ,“端點”只需要處理一件事 -與外界交互-即JSON解析部分。 如果一切都轉換為OK,它將調用一個實際完成工作的私有方法( performUpdateAll ):

def updateAll() = Action.async(parse.json) { request =>
  Json.fromJson[List[City]](request.body) match {
    case JsSuccess(givenCities, _) =>
      performUpdateAll(givenCities)
    case JsError(errors) =>
      Future.successful(BadRequest("Could not build a city from the json provided. "))
   }
}

接下來 ,我們具有執行多個城市更新的私有功能。 再次,嘗試遵守單一職責原則 (從功能上講-一個功能應該做一件事),我提取了updateCity ,它知道如何精確地更新一個城市並返回Future[UpdateWriteResult] 這樣的好處是代碼重用。 您可能會發現可以在其他地方使用此功能。

private def performUpdateAll(givenCities:List[City]):Future[Result] = {

  val updateFutures = givenCities.map { city =>
    updateCity(city)
  }

  Future.sequence(updateFutures).map { listOfResults =>
    if (listOfResults.forall(_.ok)) {
      val count = listOfResults.map(_.n).sum
      Ok(s"Updated $count cities")          
    } else {
      InternalServerError("Error updating cities")
    }
  }
}

據我所知,這將與您希望的工作方式完全相同。 但是,通過使用Future.map而不是其較低級別的對等方Future.onComplete並在SuccessFailure上進行匹配,您可以獲得更簡潔的代碼(在我看來),因為圍繞着它的樣板更少,因此更容易看到意圖

我們仍然使用以下方法檢查每個更新是否有效:

if (listOfResults.forall(_.ok)) 

我認為這很不錯-所有結果都必須正確!

我整理的另一個小技巧是用單行代碼替換使用可變變量的“計數”邏輯:

var count = 0
for {
  updateWriteResult <- s.value
} yield count += updateWriteResult.n 

變為:

val count = listOfResults.map(_.n).sum

例如,將結果列表轉換為整數列表( UpdateWriteResultn ),然后使用列表上可用的內置sum函數完成其余操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM