Joh*_*Doe 6 scala playframework
我最近阅读了Manuel Bernhardt的新书Reactive Web Applications.在他的书中,他指出Scala开发人员永远不应该使用.get来检索可选值.
我想提出他的建议,但我正在努力避免.get使用期货的理解.
假设我有以下代码:
for {
avatarUrl <- avatarService.retrieve(email)
user <- accountService.save(Account(profiles = List(profile.copy(avatarUrl = avatarUrl)))
userId <- user.id
_ <- accountTokenService.save(AccountToken.create(userId, email))
} yield {
Logger.info("Foo bar")
}
Run Code Online (Sandbox Code Playgroud)
通常,我会用AccountToken.create(user.id.get, email)而不是AccountToken.create(userId, email).但是,当试图避免这种不良做法时,我得到以下异常:
[error] found : Option[Nothing]
[error] required: scala.concurrent.Future[?]
[error] userId <- user.id
[error] ^
Run Code Online (Sandbox Code Playgroud)
我怎么解决这个问题?
如果你真的想要使用for理解,你必须将它分成几个fors,其中每个都使用相同的monad类型:
for {
avatarUrl <- avatarService.retrieve(email)
user <- accountService.save(Account(profiles = List(profile.copy(avatarUrl = avatarUrl)))
} yield for {
userId <- user.id
} yield for {
_ <- accountTokenService.save(AccountToken.create(userId, email))
}
Run Code Online (Sandbox Code Playgroud)
另一种选择是,以避免Future[Option[T]]完全和使用Future[T]它可以兑现到Failure(e)哪里e是NoSuchElementException当你想到一个None(在你的情况下,accountService.save()法):
def saveWithoutOption(account: Account): Future[User] = {
this.save(account) map { userOpt =>
userOpt.getOrElse(throw new NoSuchElementException)
}
}
Run Code Online (Sandbox Code Playgroud)
然后你会有:
(for {
avatarUrl <- avatarService.retrieve(email)
user <- accountService.saveWithoutOption(Account(profiles = List(profile.copy(avatarUrl = avatarUrl)))
_ <- accountTokenService.save(AccountToken.create(user.id, email))
} yield {
Logger.info("Foo bar")
}) recover {
case t: NoSuchElementException => Logger.error("boo")
}
Run Code Online (Sandbox Code Playgroud)
回归map/ flatMap并介绍中间结果.