我如何清理这段丑陋的 Scala 代码

Ale*_*nic 0 monads scala

这是一个非常简单的用例,但我没有找到任何优雅的方法来处理它。

下面是我正在尝试做的事情。说的很清楚了...

注意: users.byEmail返回一个Future[Option[User]].

override def invokeBlock[A](request: Request[A], block: UserRequest[A] => Future[Result]): Future[Result] = {
  val useEmail: Option[String] = request.session.get("userEmail")
  if (useEmail.isEmpty) {
    return Future.successful(Results.Unauthorized(("No email")))
  }
  val user: Option[User] = Await.result(users.byEmail(useEmail.get), Duration(1, TimeUnit.MINUTES))
  if (user.isEmpty) {
    return Future.successful(Results.Unauthorized(("No user")))
  }
  block(UserRequest(user.get, request))
}
Run Code Online (Sandbox Code Playgroud)

写这个的“正确”方法是什么?

Tim*_*Tim 5

这是一个更干净的版本:

def invokeBlock[A](request: Request[A], block: UserRequest[A] => Future[Result]): Future[Result] =
  request.session.get("userEmail") match {
    case None =>
      Future.successful(Results.Unauthorized(("No email")))
    case Some(useEmail) =>
      users.byEmail(useEmail).flatMap {
        case None =>
          Future.successful(Results.Unauthorized("No user"))
        case Some(user) =>
          block(UserRequest(user, request))
      }
  }
Run Code Online (Sandbox Code Playgroud)

关键的变化是

使用match而不是if在Option课堂上

不要使用return,这很少有必要,并且可能不会做您认为的事情

使用flatMap上Future,而不是Await.result以避免阻塞

  • 最好的方法是每个步骤在出错时生成 Future.failed,而不是 Future.successful。然后您可以使用“flatMap”或“for”链接操作列表 (2认同)