我有两个相似的功能。一个成功后返回一个String,第二个成功时返回一个Option [String]。如何以更优雅的方式编写它,也许在第二个函数中调用第一个函数?谢谢!
private def readString(j: JsValue, key: String): Validation[String, String] = {
j \ key match {
case j: JsString =>
Success(j.value)
case j: JsUndefined =>
Failure(s"Missing field $key")
case j: JsValue =>
Failure(s"Field $key value is not a string")
}
}
private def readStringOpt(j: JsValue, key: String): Validation[String, Option[String]] = {
(j \ key).as[JsValue] match {
case j: JsString =>
j.value.some.success
case j: JsUndefined =>
None.success
case x =>
Failure(s"Field $key value is not a string")
}
}
答案 0 :(得分:2)
首先,你的第二个方法中的.as[JsValue]
并不是必需的 - 它所做的只是查找Reads
的{{1}}实例,它只是通过它的参数而永远不会失败
如果你想走上面你建议的路线(根据另一个定义JsValue
- 更少的版本),Scalaz提供了一些稍微简洁的语法:
Opt
但是,这会在最新版本的Scalaz中提供弃用警告,因为def readString(j: JsValue, key: String): Validation[String, String] =
readStringOpt(j, key).flatMap(_.toSuccess(s"Missing field $key"))
没有monad实例且其Validation
有点谎言。这意味着您有两个选项(除了忽略弃用警告):您可以切换到flatMap
,这是monadic,或者您可以使用折叠代替:
\/
哪个更冗长,但它会让你站在验证的右侧 - 不是一个单身的神。