玩 Scala 2.4 链接异步调用
Play Scala 2.4 linking asynchronous calls
我正在尝试弄清楚如何 link 多个异步调用和 return 结果。我目前正在尝试先异步用户数据,然后异步更新用户数据和 return 结果,但它似乎不起作用:(
我使用了 map { result => Ok(result)},但 play 仍然认为我在 returning 一个对象。有帮助吗?
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("")))
}
}
}
})
}
我遇到问题的主要部分是这部分。我认为这是一些语法问题。有人可以帮忙吗?
谢谢
updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map { result =>
Ok("please")
}
问题出在您的类型上,它们与所需的类型不匹配。
.fold
必须在两个分支(错误和成功分支)中产生 Future[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
将 return 与 Future[X]
并且当你映射它时你将有 Future[Y]
其中 Y
将是 userCheck => ...
的计算结果为。
在这种情况下,类型完全混淆了,因为当你在真分支上做 if(usercheck)
时,你在假分支上做 Future[Result]
,你有 Result
。因此,类型在两个分支上都不对齐,这是一个大问题,编译器将从中推断出 Any
。
要解决此问题,请在 false 分支中创建一个未来:Future.successful(BadRequest(....))
好的,既然我们解决了最内在的类型问题,让我们开始倒退。在里面我们有 Future[Result]
,如果我们返回一级(在 getUser()
之前),那么我们将有 Future[Future[Result]]
。同样,这不是我们想要的,因为我们需要 Future[Result]
.
解决这个问题的方法是 flatMap
而不是 map
,因为使用 flatMap
时,当您需要 return 相同的容器类型时,它会将其展平。一个简单的例子来理解这一点:
Seq(1, 2, 3).flatMap(i => Seq(i, i))
// res0: Seq[Int] = List(1, 1, 2, 2, 3, 3)
在Future
s的情况下:
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
Future(1).flatMap(i => Future(i*2))
// res1: scala.concurrent.Future[Int] = [....]
所以我们看到我们没有双重嵌套,只有一个Future
。
回到你的例子,这将是我更新后的代码,效果会更好:
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
}
})
}
我正在尝试弄清楚如何 link 多个异步调用和 return 结果。我目前正在尝试先异步用户数据,然后异步更新用户数据和 return 结果,但它似乎不起作用:( 我使用了 map { result => Ok(result)},但 play 仍然认为我在 returning 一个对象。有帮助吗?
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("")))
}
}
}
})
}
我遇到问题的主要部分是这部分。我认为这是一些语法问题。有人可以帮忙吗? 谢谢
updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map { result =>
Ok("please")
}
问题出在您的类型上,它们与所需的类型不匹配。
.fold
必须在两个分支(错误和成功分支)中产生 Future[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
将 return 与 Future[X]
并且当你映射它时你将有 Future[Y]
其中 Y
将是 userCheck => ...
的计算结果为。
在这种情况下,类型完全混淆了,因为当你在真分支上做 if(usercheck)
时,你在假分支上做 Future[Result]
,你有 Result
。因此,类型在两个分支上都不对齐,这是一个大问题,编译器将从中推断出 Any
。
要解决此问题,请在 false 分支中创建一个未来:Future.successful(BadRequest(....))
好的,既然我们解决了最内在的类型问题,让我们开始倒退。在里面我们有 Future[Result]
,如果我们返回一级(在 getUser()
之前),那么我们将有 Future[Future[Result]]
。同样,这不是我们想要的,因为我们需要 Future[Result]
.
解决这个问题的方法是 flatMap
而不是 map
,因为使用 flatMap
时,当您需要 return 相同的容器类型时,它会将其展平。一个简单的例子来理解这一点:
Seq(1, 2, 3).flatMap(i => Seq(i, i))
// res0: Seq[Int] = List(1, 1, 2, 2, 3, 3)
在Future
s的情况下:
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
Future(1).flatMap(i => Future(i*2))
// res1: scala.concurrent.Future[Int] = [....]
所以我们看到我们没有双重嵌套,只有一个Future
。
回到你的例子,这将是我更新后的代码,效果会更好:
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
}
})
}