播放Scala 2.4链接异步调用

播放Scala 2.4链接异步调用,scala,asynchronous,playframework,playframework-2.0,Scala,Asynchronous,Playframework,Playframework 2.0,我试图找出如何链接多个异步调用并返回结果。我目前正在尝试先异步更新用户数据,然后异步更新用户数据并返回结果,但它似乎不起作用:( 我使用了map{result=>Ok(result)},但play仍然认为我返回了一个对象。有什么帮助吗 def updateUserData() = Action.async { implicit request => updateUserForm.bindFromRequest.fold( errors => Future.successful(Bad

我试图找出如何链接多个异步调用并返回结果。我目前正在尝试先异步更新用户数据,然后异步更新用户数据并返回结果,但它似乎不起作用:( 我使用了map{result=>Ok(result)},但play仍然认为我返回了一个对象。有什么帮助吗

def updateUserData() = Action.async { implicit request =>
updateUserForm.bindFromRequest.fold(
errors => Future.successful(BadRequest(views.html.authenticated.settings.settings_hero(errors, Option(""), Option("")))),
{
  case (userData) =>
    request.session.get("email") match {
      case Some(email) =>
        getUser(email, userData.curent_password) map { userCheck =>
          if (userCheck) {
            updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map { result =>
              Ok("please")
            }
            //val e = updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map {result => Ok("")}

            // user is valid now update the user data

            // call removeAuth to log out

            // redirect to home
            ///Ok (updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map { result => result})
            //Redirect(routes.settings.index()).addingToSession("email" -> email)
          } else {
            BadRequest(views.html.authenticated.settings.settings_hero(updateUserForm.bindFromRequest.withGlobalError(Messages("error.login", email)), Option(""), Option("")))
          }
        }
      }
  })
}
我遇到的主要问题是这一部分。我想这是一些语法问题。有人能帮忙吗? 谢谢


问题在于您的类型,它们与所需的类型不匹配

.fold
必须在两个分支(错误分支和成功分支)中产生
未来[result]

在成功的表单绑定分支中,您有以下内容:

case (userData) => ... // The ... must evaluate to Future[Result]
查看您的第一次操作,我们看到:

request.session.get("email") match {
  case Some(email) => ...
}
这里的一个大问题是未处理
None
案例!(但这不会导致类型不匹配)。使用类似于以下内容的方法可以解决此问题:
case None=>Future.successful(BadRequest(…)

因此,继续前进:在
Some
中,您有以下内容:

getUser(email, userData.curent_password) map { userCheck =>
  if (userCheck) {
    updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map { result =>
       Ok("please")
    }
  } else {
    BadRequest(views.html.authenticated.settings.settings_hero(updateUserForm.bindFromRequest.withGlobalError(Messages("error.login", email)), Option(""), Option("")))
  }
}
这就是问题所在:

getUser
将返回一个
Future[X]
,当您映射到它时,您将得到
Future[Y]
,其中
Y
将是
userCheck=>…
的计算结果

在这种情况下,类型是完全混合的,因为当你在真分支上执行
if(usercheck)
时,你有
Future[Result]
在假分支上,你有
Result
。因此类型在两个分支上都不对齐,这是一个大问题,编译器将由此推断出
Any

要解决此问题,请在false分支中创建一个future:
future.successful(BadRequest(..)

好的,现在我们已经解决了大多数内部类型问题,让我们开始向后看。在内部我们有
Future[Result]
,如果我们返回一个级别(在
getUser()
之前),那么我们将有
Future[Future[Result]]
。这又不是我们想要的,因为我们需要
Future[Result]

解决此问题的方法是使用
flatMap
而不是
map
,因为使用
flatMap
时,您需要返回相同的容器类型并将其展平。了解此问题的快速示例如下:

Seq(1, 2, 3).flatMap(i => Seq(i, i))
// res0: Seq[Int] = List(1, 1, 2, 2, 3, 3)
未来的情况下
s:

import scala.concurrent.Future   
import scala.concurrent.ExecutionContext.Implicits.global
Future(1).flatMap(i => Future(i*2))
// res1: scala.concurrent.Future[Int] = [....]
所以我们看到我们没有双重嵌套,只有一个未来的

回到您的示例,这将是我更新的代码,可以更好地工作:

def updateUserData() = Action.async { implicit request =>
  updateUserForm.bindFromRequest.fold(
    errors => Future.successful(BadRequest(views.html.authenticated.settings.settings_hero(errors, Option(""), Option("")))),
    {
      case (userData) =>
        request.session.get("email") match {
          case Some(email) =>
            getUser(email, userData.curent_password).flatMap { userCheck =>
              if (userCheck) {
                updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map { result =>
                  Ok("please")
                }
              } else {
                Future.successful(BadRequest(views.html.authenticated.settings.settings_hero(updateUserForm.bindFromRequest.withGlobalError(Messages("error.login", email)), Option(""), Option(""))))
              }
            }
        case None => Future.successful(BadRequest) // FIXME: Implement as you wish
        }
    })
}

你能分享方法签名(更具体地说是返回类型)吗:
getUser
updateUserOnService
。没有它,我们很难在脑海中推断出类型:)def updateUserOnService(email:String,firstName:String,lastName:String,n_密码:String)={WS.url(“).post(Map(“email”->Seq(email),“firstName”->Seq(firstName),“lastName”->Seq(lastName),“n_password”->Seq(n_password)))def getUser(email:String,password:String)={WS.url(“).post(Map”(“email”->Seq(email),“password”->Seq(password))).Map(response=>response.body.contains(“true”)}对不起,我是个新手,因此,我不知道如何编辑或重新格式化代码,以便让你们更容易看到:(嘿,非常感谢!我无法提高你们的投票率,因为我没有足够的声誉:(它现在起作用了!我知道类型是问题所在:(@ShawnYoon)如果您发现这回答了问题,请使用绿色复选标记将其标记为已回答。
def updateUserData() = Action.async { implicit request =>
  updateUserForm.bindFromRequest.fold(
    errors => Future.successful(BadRequest(views.html.authenticated.settings.settings_hero(errors, Option(""), Option("")))),
    {
      case (userData) =>
        request.session.get("email") match {
          case Some(email) =>
            getUser(email, userData.curent_password).flatMap { userCheck =>
              if (userCheck) {
                updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map { result =>
                  Ok("please")
                }
              } else {
                Future.successful(BadRequest(views.html.authenticated.settings.settings_hero(updateUserForm.bindFromRequest.withGlobalError(Messages("error.login", email)), Option(""), Option(""))))
              }
            }
        case None => Future.successful(BadRequest) // FIXME: Implement as you wish
        }
    })
}