我正在使用 Scala 使用安全的社交和 reactivemongo 库编写一个 play 2.3 应用程序。 现在我正在尝试实现 UserService[T] 特性,但我在 updatePasswordInfo 方法上遇到编译错误。 这是方法:
def updatePasswordInfo(user: LoginUser,info: PasswordInfo): scala.concurrent.Future[Option[BasicProfile]] = {
implicit val passwordInfoFormat = Json.format[PasswordInfo]
//the document query
val query = Json.obj("providerId" -> user.providerId,
"userId" -> user.userId
)
//search if the user exists
val futureUser: Future[Option[LoginUser]] = UserServiceLogin.find(query).one
futureUser map {
case Some(x) => val newPassword = Json.obj("passswordInfo" -> info)// the new password
UserServiceLogin.update(query, newPassword) //update the document
val newDocument: Future[Option[LoginUser]] = UserServiceLogin.find(query).one
newDocument map {
case Some(x) => x
case None => None
} //return the new LoginUser
case None => None
}
}
这是编译器错误:
/Users/alberto/git/recommendation-system/app/security/UserService.scala:203: type mismatch;
[error] found : scala.concurrent.Future[Product with Serializable]
[error] required: Option[securesocial.core.BasicProfile]
[error] newDocument map {
怎么了?
最佳答案
如果您映射到 Future[A]
,您最终会得到一个 Future[B]
,其中 T
是类型从传递给 map
的 lambda 返回。
由于 lambda 返回一个 Future[B]
在这种情况下你最终得到一个 Future[Future[B]]
,这与预期不匹配类型。
简单的解决方法是使用 flatMap
,它需要一个从 A
到 Future[B]
的 lambda。
此外,您要返回一个 Option[LoginUser]
,但该方法应该返回一个 Option[BasicProfile]
。编译器推断出一个通用父类(super class)型,在本例中为 Product with Serializable
,因为它们都是案例类。
总结一下
scala.concurrent.Future[Product with Serializable]
^_____________________^^_________________________^
1 2
- 使用
flatMap
代替map
- 返回
BasicProfile
而不是LoginUser
,或者将方法返回类型更改为Future[Option[LoginUser]]
顺便说一下,还有很大的改进空间,因为您可以使用 for-comprehension 和来自 scalaz 的 OptionT
monad 转换器来使整个事情更漂亮。
举个例子
import scalaz._; import Scalaz._
val newPassword = Json.obj("passswordInfo" -> info)
(for {
// this is done only for failing fast in case the user doesn't exist
_ <- optionT(UserServiceLogin.find(query).one)
_ <- optionT(Future.successful(Some(UserServiceLogin.update(query, newPassword))))
updatedUser <- optionT(UserServiceLogin.find(query).one)
} yield updatedUser).run
顺便说一下,这在 update
是一个同步调用的假设下工作,但可能(我希望)不是这种情况。如果它返回一个 Future[T]
只需将代码更改为
_ <- optionT(UserServiceLogin.update(query, newPassword).map(Some(_)))
或者如果它已经返回一个 Future[Option[T]]
_ <- optionT(UserServiceLogin.update(query, newPassword))
关于scala - Play 中 Future[Option[BasicProfile]] 方法的编译错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26014761/