Как я могу проверить значения параметров с помощью проверки кошек? - PullRequest
0 голосов
/ 13 февраля 2019

Я пытаюсь изменить код, который использует проверку кошек, что-то вроде:

  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)

, который работает нормально.

Но мое изменение требует, чтобы поле изображения было Option, как:

  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)

При этом mapN завершается сбоем, потому что типы внезапно различаются, он говорит:

value mapN is not a member of (cats.data.Validated[Int,String], Option[cats.data.Validated[Int,String]])

Я хочу, чтобы он проверялся только при наличии значения.Таким образом, он должен быть частью результата проверки, если значение присутствует, но игнорировать поле в противном случае.Я знаю, что есть несколько способов объединения проверок, но в моем реальном коде это было бы намного сложнее, чем что-то подобное.

Есть ли способ сделать это простым способом?Я не смог ничего найти об этом в документах или в поиске.

Спасибо за помощь!

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

Ответ 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)

Таким образом, похоже, traverse на Option делает то, что вы хотите: он проверяет содержимоеSome и игнорирует None (т.е. пропускает его как действительный).

Таким образом, вы можете написать следующее, заменив map на traverse:

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

И все готово.

0 голосов
/ 13 февраля 2019

Звоните sequence на Option[Validated[String]], на месте e.image.map(validImage)

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

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

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"))
println((validText(e.text), e.image.map(validImage).sequence).mapN(ValidExample))

производит

Valid(ValidExample(test,Some(test.png)))
...