ope*_*sas 4 error-handling scala idiomatic
以下是一个非常常见的播放框架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)))
}
Run Code Online (Sandbox Code Playgroud)
我发现所有嵌套的.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)
)
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
我想要一个方法,通过这些方法管理字符串,并返回相应的错误消息,如果我得到一个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!")
Run Code Online (Sandbox Code Playgroud)
但是,这不是很好.我们可以使用for-comprehension和toRight方法Option来编写更清晰的版本:
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
Run Code Online (Sandbox Code Playgroud)
调用toRight(msg)上Option给了我们一个Left(msg),如果它是空的,和Right(whatever)其他.然后我们必须采用Eitherwith 的正确投影.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)
)
}
Run Code Online (Sandbox Code Playgroud)
不像你想要的语法简洁,但错误消息出现在一个更合乎逻辑的地方,我们已经摆脱了丑陋的嵌套.
| 归档时间: |
|
| 查看次数: |
502 次 |
| 最近记录: |