scala - 是否有用于对没有共同祖先的类进行分组的“OneOf”类
问题描述
与此类似,我不想接受几个不相关的类之一,而是想返回一个。
我有一个使用多个底层存储库的编排服务。每个 repo 都可以传回一个错误。但是,这些错误类不共享一个共同的祖先。
例如:
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) => ...
}
根据链接的 SO 答案,我尝试了:
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)
甚至可以将此方法用于返回类型吗?
解决方案
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
本质上,它所做的只是在您调用时检查 -witness是否存在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
}
推荐阅读
- python - 如何根据一周中不同日子的不同时间段修剪数据集?
- javascript - 如何使用 ES6 缩短此功能?
- javascript - 根据输入参数在 JavaScript 中动态生成函数
- python - 如何避免 [Errno 98] 地址已在使用中
- python - Python脚本随着时间的推移变慢
- javascript - 获取乒乓球游戏的键号时无法读取未定义的属性“keyCode”
- laravel - 不存在具有关系的急切加载
- python-3.x - Selenium.common.exceptions.WebDriverException:消息:未知错误:找不到 Chrome 二进制文件
- java - 尝试在空对象引用上调用虚拟方法'boolean java.util.ArrayList.add
- postman - tv4.validate 总是返回 true。即使我的架构无效,即:var == "dummy"