如何使用Cats验证验证Option值?

Chi*_*Pro 4 validation scala scala-cats

我正在尝试更改使用猫验证的代码,例如:

  case class Example(text: String, image: String)
  case class ValidExample(text: String, image: String)

  import cats.data.Validated._
  import cats.implicits._

  def validText(text: String) = if (text.nonEmpty) text.valid else invalid(-1)
  def validImage(image: String) = if (image.endsWith(".png")) image.valid else invalid(-1)
  val e = Example("test", "test.png")
  (validText(e.text), validImage(e.image)).mapN(ValidExample)
Run Code Online (Sandbox Code Playgroud)

哪个工作正常.

但我的更改要求图像字段是一个选项,如:

  case class Example(text: String, image: Option[String])
  case class ValidExample(text: String, image: Option[String])

  import cats.data.Validated._
  import cats.implicits._

  def validText(text: String) = if (text.nonEmpty) text.valid else invalid(-1)
  def validImage(image: String) = if (image.endsWith(".png")) image.valid else invalid(-1)
  val e = Example("test", Some("test.png"))
  (validText(e.text), e.image.map(validImage)).mapN(ValidExample)
Run Code Online (Sandbox Code Playgroud)

有了这个,mapN失败了,因为类型突然不同,它说:

value mapN is not a member of (cats.data.Validated[Int,String], Option[cats.data.Validated[Int,String]])
Run Code Online (Sandbox Code Playgroud)

我希望它只验证值是否存在.因此,如果存在值,它应该是验证结果的一部分,否则忽略该字段.我知道有一些方法可以组合验证,但在我的真实代码中,这将比这样的内容更多.

有没有办法以简单的方式做到这一点?我无法在文档或搜索中找到任何相关信息.

感谢帮助!

Tra*_*own 5

答案是traverse,像往常一样 :):

scala> val exampleWithImage = Example("test", Some("test.png"))
exampleWithImage: Example = Example(test,Some(test.png))

scala> val exampleWithoutImage = Example("test", None)
exampleWithoutImage: Example = Example(test,None)

scala> val badExampleWithImage = Example("test", Some("foo"))
badExampleWithImage: Example = Example(test,Some(foo))

scala> exampleWithImage.image.traverse(validImage)
res1: cats.data.Validated[Int,Option[String]] = Valid(Some(test.png))

scala> exampleWithoutImage.image.traverse(validImage)
res2: cats.data.Validated[Int,Option[String]] = Valid(None)

scala> badExampleWithImage.image.traverse(validImage)
res3: cats.data.Validated[Int,Option[String]] = Invalid(-1)
Run Code Online (Sandbox Code Playgroud)

所以它看起来像traverseOption你想要做什么:它验证的内容Some,并忽略None(即通过为有效传递给它).

所以你可以写下面的内容,替换maptraverse:

scala> (validText(e.text), e.image.traverse(validImage)).mapN(ValidExample)
res4: cats.data.Validated[Int,ValidExample] = Valid(ValidExample(test,Some(test.png)))
Run Code Online (Sandbox Code Playgroud)

而且你已经完成了.