Similar to this,我不想返回几个不相关的类之一,而是想返回一个。
我有一个利用几个基础存储库的协调服务。每个回购可以传回错误。但是,这些错误类并不具有相同的祖先。
例如:
case class DistributionError
case class UserError
case class ContentError
我想像这样创建我的编排服务方法:
def doSomethingComplicated(): Either[TheErrors, Boolean] = {
//...
case Failure(e) => Left(new DistributionError)
//...
}
然后我将这样调用它:
doSomethingComplicated() match {
case Left(error) => {
error match {
case _: DistributionError => ...
case _: UserError => ...
case _: ContentError => ...
}
}
case Right(success) => ...
}
As per the linked SO answer,我尝试过:
class TheErrors[T]
object TheErrors {
implicit object DistWitness extends TheErrors[DistributionError]
implicit object UserWitness extends TheErrors[UserError]
implicit object ContentWitness extends TheErrors[ContentError]
}
但是它只是不能像处理参数一样工作。编译器总是抱怨:
> Error:(176, 48) type mismatch;
> found : UserError
> required: T
> case None => Left(UserError)
甚至可以将这种方法用于返回类型吗?
答案 0 :(得分:1)
AnyRef解决方案
一种快速而廉价的解决方案是删除整个TheErrors
类型类,然后从Either[AnyRef, Boolean]
返回doSomethingComplicated
。
现有类型解决方案
如果您绝对要确保doSomethingComplicated
仅返回先前在TheErrors
随播对象中明确列出的错误类型,则可以执行以下操作:
import scala.language.existentials
case class DistributionError()
case class UserError()
case class ContentError()
class TheErrors[T]
object TheErrors {
implicit object DistWitness extends TheErrors[DistributionError]
implicit object UserWitness extends TheErrors[UserError]
implicit object ContentWitness extends TheErrors[ContentError]
}
def allowedError[E](e: E)(implicit witness: TheErrors[E])
: (E, TheErrors[E]) = (e, witness)
type AllowedError = (E, TheErrors[E]) forSome { type E }
def doSomethingComplicated(): Either[AllowedError, Boolean] = {
import TheErrors._
/* sth complicated */ Left(allowedError(DistributionError()))
}
doSomethingComplicated() match {
case Left((error, _)) => {
error match {
case _: DistributionError => 42
case _: UserError => 58
case _: ContentError => 100
}
}
case Right(success) => 2345678
}
本质上,它要做的就是在您致电TheErrors
时检查是否存在allowedError
证人,并将见证人附加到错误上。这样可以确保仅从doSomethingComplicated
返回可以找到证人的错误。但是请注意,它并不能帮助您检查模式匹配的详尽性。为此,您将必须采用通常的方法,并将所有错误包装到一个常见的密封特征的子类中。
密封性状解决方案
import scala.language.implicitConversions
case class DistributionError()
case class UserError()
case class ContentError()
sealed trait TheErrors
case class Distr(e: DistributionError) extends TheErrors
case class User(e: UserError) extends TheErrors
case class Content(e: ContentError) extends TheErrors
object TheErrors {
implicit def apply(d: DistributionError): TheErrors = Distr(d)
implicit def apply(d: UserError): TheErrors = User(d)
implicit def apply(d: ContentError): TheErrors = Content(d)
}
def doSomethingComplicated(): Either[TheErrors, Boolean] = {
/* sth complicated */ Left(DistributionError())
}
doSomethingComplicated() match {
case Left(error) => {
error match {
case Distr(e) => 42
case User(e) => 58
case Content(e) => 100
}
}
case Right(success) => 2345678
}
隐式转换+普通的旧子类多态性
借助隐式转换和良好的旧子类多态性,您可以摆脱调用者代码中TheErrors
和中任何特定的doSomethingComplicated
子类:
import scala.language.implicitConversions
case class DistributionError()
case class UserError()
case class ContentError()
sealed trait TheErrors {
def error: AnyRef
}
object TheErrors {
private case class TheError(val error: AnyRef) extends TheErrors
implicit def apply(d: DistributionError): TheErrors = TheError(d)
implicit def apply(d: UserError): TheErrors = TheError(d)
implicit def apply(d: ContentError): TheErrors = TheError(d)
}
def doSomethingComplicated(): Either[TheErrors, Boolean] = {
/* sth complicated */ Left(DistributionError())
}
doSomethingComplicated() match {
case Left(e) => {
e.error match {
case _: DistributionError => 42
case _: UserError => 58
case _: ContentError => 100
}
}
case Right(success) => 2345678
}
答案 1 :(得分:1)
很少有选择:
Coproduct
type Any
Either
即Either[Either[Either[A, B], C], D]
class UserErrorWrapper(val u: UserError) extends MyErrorTrait