我将其添加为答案,因为这是我立即解决问题的方法,但我已经有一段时间没有密切关注 Argonaut 的开发了,我很想听到有一个更好的方法。首先是设置,它修复了您的一些小问题,并添加了名称有效性的条件,以使后面的示例更有趣:
import scalaz._, Scalaz._
case class Person private(name: String, age: Int)
object Person {
def validAge(age: Int): ValidationNel[String, Int] =
if (age > 18) age.successNel else "Age is under 18".failureNel
def validName(name: String): ValidationNel[String, String] =
if (name.size >= 3) name.successNel else "Name too short".failureNel
def create(name: String, age: Int) =
(validName(name) |@| validAge(age))(Person.apply)
}
然后我将 JSON 解码为(String, Int)
在创建之前配对Person
:
import argonaut._, Argonaut._
def decodePerson(in: String): ValidationNel[String, Person] =
Parse.decodeValidation(in)(
jdecode2L((a: String, b: Int) => (a, b)
)("name", "age")).toValidationNel.flatMap {
case (name, age) => Person.create(name, age)
}
进而:
scala> println(decodePerson("""{ "name": "", "age": 1 }"""))
Failure(NonEmptyList(Name too short, Age is under 18))
请注意,在更复杂的情况下,这不会累积错误 - 例如如果的值name
字段是一个数字并且age
is 1
,你只会得到一个错误(name
一)。在这种情况下,使错误累积发挥作用将要复杂得多。
相关地,您还会看到有关以下内容的弃用警告flatMap
on Validation
,您可以将其视为提醒,累积不会跨界发生。您可以通过导入告诉编译器您理解scalaz.Validation.FlatMap._
.