[英]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.