加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala:提高这段代码的可读性和风格

发布时间:2020-12-16 18:03:45 所属栏目:安全 来源:网络整理
导读:以下是一个非常常见的播放框架2控制器: def save(ideaId : Long) = CORSAction { request = Idea.findById(ideaId).map { idea = request.body.asJson.map { json = json.asOpt[Comment].map { comment = comment.copy(idea = idea).save.fold( errors = Js
以下是一个非常常见的播放框架2控制器:

def save(ideaId : Long) = CORSAction { request =>
  Idea.findById(ideaId).map { idea =>
    request.body.asJson.map { json =>
      json.asOpt[Comment].map { comment =>
        comment.copy(idea = idea).save.fold(
          errors => JsonBadRequest(errors),comment => Ok(toJson(comment).toString)
        )
      }.getOrElse     (JsonBadRequest("Invalid Comment entity"))
    }.getOrElse       (JsonBadRequest("Expecting JSON data"))
  }.getOrElse         (JsonBadRequest("Could not find idea with id '%s'".format(ideaId)))
}

我发现所有嵌套的.maps都有点烦人,我也发现每个错误处理都在底部有点乏味

您将如何改进它以使其更具可读性,同时保持功能惯用的scala代码?

我想也许是这样的(它是seudo代码,仍然无法编译)

def save(ideaId : Long) = CORSAction { request =>

  val idea = Idea.findById(ideaId).getOrElse(
    return JsonBadRequest("Could not find idea with id '%s'".format(ideaId)))

  val json = request.body.asJson.getOrElse(
    return JsonBadRequest("Expecting JSON data"))

  val comment = json.asOpt[Comment].getOrElse(
    return JsonBadRequest("Invalid Comment entity"))

  comment.copy(idea = idea).save.fold(
    errors => JsonBadRequest(errors),comment => Ok(toJson(comment).toString)
  )

}

ps:我知道避免退货声明会好得多……

解决方法

首先要简化.假设我有三个方法接受一个String并返回一个Option [String]:

def foo(s: String): Option[String] = if (s.size >= 4) Some(s + "1") else None
def bar(s: String): Option[String] = if (s(0) != 'A') Some(s + "2") else None
def baz(s: String): Option[String] = if (s toSet ' ') Some(s + "3") else None

我想要一个方法,通过这些方法管理字符串,并返回相应的错误消息,如果我一路上得到一个无.我可以这样写:

def all(s: String): Either[String,String] =
  foo(s).map { x =>
    bar(x).map { y =>
      baz(y).map { z =>
        Right(z)
      } getOrElse Left("Doesn't contain a space!")
    } getOrElse   Left("Starts with an A!")
  } getOrElse     Left("Too short!")

但是,这不是很好.我们可以使用for-comprehension和Option上的toRight方法来编写更清晰的版本:

def all(s: String): Either[String,String] = for {
  x <- (foo(s) toRight "Too short!"              ).right
  y <- (bar(x) toRight "Starts with an A!"       ).right
  z <- (baz(y) toRight "Doesn't contain a space!").right
} yield z

在Option上调用toRight(msg)如果它为空则给我们一个Left(msg),否则给我们一个Right(无论如何).然后,我们必须使用.right进行正确的投影,因为Scala的Either不是正确的.

您的情况中的等价物将是这样的:

def save(ideaId: Long) = CORSAction { request =>
  val saveResult = for {
    idea    <- (Idea.findById(ideaId) toRight "Could not find id"     ).right
    json    <- (request.body.asJson   toRight "Invalid Comment entity").right
    comment <- (json.asOpt[Comment]   toRight "Expecting JSON data"   ).right
    result  <- comment.copy(idea = idea).save().right
  } yield result

  saveResult.fold(
    error => JsonBadRequest(error),comment => Ok(toJson(comment).toString)
  )
}

不像你想要的语法简洁,但错误消息出现在一个更合乎逻辑的地方,我们已经摆脱了丑陋的嵌套.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读