yi.*_*han 4 error-handling scala either
我是Scala的新手。AFAIK,Either封装故障处理,允许链式操作,而无需重复编写样板代码。它还允许电路中断执行的继续。但这可能并不总是我想要的。例如,对于以下代码,如果name和age均无效,则该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)
以下是使用@Luis Validated并Parallel建议使用的错误累积示例:
Validatedimport 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所有错误均已累积。
Parallelimport 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所有错误均已累积。