繁体   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