如何使用Either产生所有错误(故障)

yi.*_*han 4 error-handling scala either

我是Scala的新手。AFAIK,Either封装故障处理,允许链式操作,而无需重复编写样板代码。它还允许电路中断执行的继续。但这可能并不总是我想要的。例如,对于以下代码,如果nameage均无效,则该makePerson函数将不会同时返回两个错误

你们能建议一种方法吗?

case class Person(name: Name, age: Age)
sealed class Name(val value: String)
sealed class Age(val value: Int)

case class Person(name: Name, age: Age){

}
sealed class Name(val value: String)
sealed class Age(val value: Int)

object Person{
    def makeName(name: String): Either[String, Name] = {
        if (name == "" || name == null) Left("Name is empty.") else Right(new Name(name))
    }

    def makeAge(age: Int): Either[String, Age] = {
        if (age < 0) Left("Age is out of range.") else Right(new Age(age))
    }

    def makePerson(name: String, age: Int): Either[String, Person] = {
        mkName(name).map2(mkAge(age))(Person(_, _))
    }
}
Run Code Online (Sandbox Code Playgroud)
    def map2[EE >: E, B, C](b: Either[EE, B])(f: (A, B) => C): Either[EE, C] = {
            val func = (aa: A) => b.map(bb => f(aa, bb))
            this.flatMap(func)
    }


    def flatMap[EE >: E, B](f: A => Either[EE, B]): Either[EE, B] = this match {
        case Left(e) => Left(e)
        case Right(a) => f(a)
    }

Run Code Online (Sandbox Code Playgroud)

Mar*_*lic 5

以下是使用@Luis ValidatedParallel建议使用的错误累积示例:

Validated

import cats.data.ValidatedNec
import cats.implicits._

case class Person(name: Name, age: Age)
case class Name(value: String)
case class Age(value: Int)

object validatedPerson extends App {
  private def validateName(name: String): ValidatedNec[String, Name] =
    if (name == "" || name == null) "Name is empty.".invalidNec else Name(name).validNec

  private def validateAge(age: Int): ValidatedNec[String, Age] =
    if (age < 0) "Age is out of range.".invalidNec else Age(age).validNec


  def validatePerson(name: String, age: Int): ValidatedNec[String, Person] = {
    (validateName(name), validateAge(age)).mapN(Person)
  }

  println(validatePerson(name = "Joe", age = 21))
  println(validatePerson(name = "", age = -42))
}
Run Code Online (Sandbox Code Playgroud)

哪个输出

Valid(Person(Name(Joe),Age(21)))
Invalid(Chain(Name is empty., Age is out of range.))
Run Code Online (Sandbox Code Playgroud)

在这里,我们可以看到Invalid所有错误均已累积。

Parallel

import cats.data.{EitherNel, NonEmptyList}
import cats.instances.parallel._
import cats.syntax.parallel._

object parValidatedPerson extends App {
  private def validateName(name: String): EitherNel[String, Name] =
    if (name == "" || name == null) Left(NonEmptyList.one("Name is empty.")) else Right(Name(name))

  private def validateAge(age: Int): EitherNel[String, Age] =
    if (age < 0) Left(NonEmptyList.one("Age is out of range.")) else Right(Age(age))


  def validatePerson(name: String, age: Int): Either[NonEmptyList[String], Person] = {
    (validateName(name), validateAge(age)).parTupled.map(Person.tupled)
  }

  println(validatePerson(name = "Joe", age = 21))
  println(validatePerson(name = "", age = -42))
}

Run Code Online (Sandbox Code Playgroud)

哪个输出

Right(Person(Name(Joe),Age(21)))
Left(NonEmptyList(Name is empty., Age is out of range.))
Run Code Online (Sandbox Code Playgroud)

在这里,我们可以看到Left所有错误均已累积。

  • 您知道,提供高质量的答案不会让您感到难过;)-大部分时间我无法写完整的答案,可能是因为打电话或没有时间。但是,由于我只想提供帮助,所以我尝试编写有用的评论。因此,我很高兴人们发现他们有价值,并且其他人可以提供很好的答案!-顺便说一句,现在我并不是很在乎这些要点,当时达到我的第一个1K的水平也是很酷的,我也是这个时期的第一个,我记得我已经在所有社交媒体上发布了!但是,不久之后,我意识到我真的不在乎要点,而是在提供帮助。 (2认同)