[英]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
並在Success
與Failure
上進行匹配,您可以獲得更簡潔的代碼(在我看來),因為圍繞着它的樣板更少,因此更容易看到意圖 。
我們仍然使用以下方法檢查每個更新是否有效:
if (listOfResults.forall(_.ok))
我認為這很不錯-所有結果都必須正確!
我整理的另一個小技巧是用單行代碼替換使用可變變量的“計數”邏輯:
var count = 0
for {
updateWriteResult <- s.value
} yield count += updateWriteResult.n
變為:
val count = listOfResults.map(_.n).sum
例如,將結果列表轉換為整數列表( UpdateWriteResult
的n
),然后使用列表上可用的內置sum
函數完成其余操作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.