【问题标题】:How can I get this for-comprehension to return?我怎样才能让这个理解返回?
【发布时间】:2019-06-13 19:51:14
【问题描述】:

我正在创建一个与服务对话的控制器。控制器(基于 Play 库AbstractController)接受一个隐式请求并返回一个Future[Result]。该服务收到一个请求并返回一个Future[Model]。我有一些条件要防止创建模型。例如,如果用户没有访问权限,则不应创建任何模型。

 def create(): Action[JsValue] = Action(parse.tolerantJson).async { implicit request: Request[JsValue] =>
    val modelOpt: Option[Future[Result]] =  // I've tried Future[Result] here too
      for {
        attributes <- (request.body \ "data" \ "attributes").validate[JsObject].asOpt
        userOpt = (request.body \ "data" \ "attributes" \ "user-name").validate[String].asOpt
        user <- userOpt
        model <- service1.createModel(user) // Create Model returns type of Future[Model], so this should flatMap to Model
      } yield {
        val permission = checkPermission(user)  // Returns true or false, depending on if the user is permissioned
        (userOpt, permission) match {
          case (Some(_), true) => Ok(model)
          case (Some(_), false) => Forbidden
          case (None, _) => NotFound 
          case (_, false) => Forbidden 
        }
      }

    modelOpt.getOrElse(Future { InternalServerError })
  }

但是,编译器抱怨说它需要一个Option[Future[Result]],它收到一个Future[Result](可能是因为我为modelOpt 提供的类型)。但是,我认为如果 Json 无法验证它会给我None,所以我认为外部类型确实必须是一个选项。谁能告诉我这是怎么回事?

【问题讨论】:

  • 如果您可以将代码缩减为 minimal reproducible example,这可能会有所帮助。切线:Future { InternalServerError } 不会因 InternalServerError 而失败;你想要Future { throw InternalServerError },或者更好的是Future.failed(InternalServerError)
  • 你能发布完整的错误吗?
  • 如果 service1.createModel(user) 返回 Future[A],而其他从理解返回 Option[T] 它不兼容,因为你应该只使用相同的幺半群。
  • 我不认为 Future.failed 会起作用,因为InternalServerError 是不可抛出的。 @BrianMcCutchon

标签: scala playframework future for-comprehension


【解决方案1】:

如果您查看特征 Option[A] 中方法 getOrElse 的签名:

final def getOrElse[B >: A](default: => B): B

它解开Option 以返回A 或其超类型,直到B

现在,使用 modelOpt 和 Option[Future[Result]],应用 getOrElse 和类型为 Future[Result](或其子类型)的给定默认值将产生 Future[Result]

类似于getOrElse 的工作方式,但保持Option 不变,方法orElse 具有以下签名:

final def orElse[B >: A](alternative: => Option[B]): Option[B]

因此,像下面这样将orElse 应用于modelOpt 将返回所需的Option[Future[Result]]

modelOpt.orElse(Some(Future.successful(InternalServerError)))

请注意,Future.successful 用于为已完成的 Future 提供指定结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多