scala方法/播放框架/休息中的检查错误

时间:2017-07-26 22:20:40

标签: scala playframework

我还在学习scala,所以这可能是一个简单回答的问题,但我一直坚持写一个方法一遍又一遍,无法编译这段代码

我正在玩Play Framework和一个反应性mongo模板,以了解Scala和Play如何工作。 我有一个带有一些方法的控制器,一个用于REST服务的端点。

问题在于以下方法,该方法接受json对象列表并使用mongo被动驱动程序更新这些对象。该类有一个成员dir1 = './INPUT/rectifiedimages/im1_rec.jpg' dir2 = './INPUT/rectifiedimages/im2_rec.jpg' image1 = cv2.imread(dir1, 0) # queryimage # left image image2 = cv2.imread(dir2, 0) # trainimage # right image # Initiate SIFT detector orb = cv2.ORB_create() # find the keypoints and descriptors with SIFT kp1, des1 = orb.detectAndCompute(image1,None) kp2, des2 = orb.detectAndCompute(image2,None) # BFMatcher with default params bf = cv2.BFMatcher() matches = bf.knnMatch(des1, des2, k=2) # Apply ratio test good = [] for m,n in matches: if m.distance <= 1.*n.distance: good.append(m) src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2) dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2) F, maskF = cv2.findFundamentalMat(src_pts, dst_pts, cv2.RANSAC, 1., 1.) # cv2.CV_FM_LMEDS cv2.RANSAC #--- remove masked points outliers good = [good[i] for i,v in enumerate(maskF) if v[0] == 1] src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2) dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2) H, maskH = cv2.findHomography(src_pts, dst_pts, cv2.FM_LMEDS, 0., 0.99) mask = maskH matchesMask = mask.ravel().tolist()[![enter image description here][1]][1] # cv2.drawMatchesKnn expects list of lists as matches. draw_params = dict(matchColor = (0,255,0), # draw matches in green color singlePointColor = (0,0,255), matchesMask = matchesMask, # draw only inliers flags = 0) img3 = cv2.drawMatches(image1, kp1, image2, kp2,good, None,**draw_params) ,其类型为citiesFuture。 我可以在此处找到我添加此方法的原始类代码:CityController on github

Future[JSONCollection]

我已经设法通过大量的试验和错误来实现这一目标,但是我开始理解scala和Futures的一些机制是如何工作的,我认为:)我认为我&#39; m close,但我的IDE仍然只在行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))) } } 上方的单个结束大括号上给出了一个检查错误。

错误如下:单位类型的表达式不符合预期类型Nothing 。 我已经检查了Promise和onComplete代码块的预期返回值,但我不相信他们希望 Nothing 作为返回类型。

有人可以向我解释一下我错过了什么,而且,我确信这可以做得更好,所以如果你有任何我可以学习的提示,请告诉我!

1 个答案:

答案 0 :(得分:1)

你有点走在正确的轨道上,但正如@cchantep所说,一旦你在Future - 土地上运作,你需要创建自己的{{1}是非常不寻常的}}

此外,看到Promise.future被使用实际上是非常不寻常的 - 惯用的Scala通常偏向于更高级别的&#34;对期货的onComplete ping的抽象。我将尝试演示如何在Play控制器中编写您的功能:

首先,&#34;端点&#34;只需处理一件事 - 与外界联系 - 即JSON解析部分。如果一切都转换为OK,它会调用一个实际完成工作的私有方法(map):

performUpdateAll

下一步,我们有私有功能,可以执行多个城市的更新。再次,尝试遵守Single Responsibility Principle(在功能意义上 - 一个功能应该做一件事),我已经提取出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. ")) } } 知道如何更新一个城市< / em>并返回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.onCompleteSuccess,您可以获得更简洁的代码(在我看来)&#39;更容易看到意图因为它周围的样板很少。

我们仍然会检查每次更新是否都有效:

Failure

我认为读得很好 - 所有结果都必须好!

我做的另一个小技巧就是更换你的&#34;计数&#34;使用可变变量的逻辑,带有单行:

if (listOfResults.forall(_.ok)) 

变为:

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

即。将结果列表转换为整数列表(val count = listOfResults.map(_.n).sum 中的n),然后使用列表中提供的内置UpdateWriteResult函数来完成剩下的工作。