我的应用程序有两层:域和应用程序。每层都有自己的“错误”ADT。例如:
package com.domain.person
sealed trait DomainError
case object NoPermission extends DomainError
final case class Person(hasPermission: Boolean): Either[DomainError, ???] {
def doSomething() = {
if (!hasPermission)
Left(NoPermission)
else
...
}
}
Run Code Online (Sandbox Code Playgroud)
在我的应用程序层(另一个包)中:
package com.application.person
sealed trait ApplicationError
case object PersonNotFound extends ApplicationError
case object UnexpectedFatalError extends ApplicationError
// and a function f :: Either ApplicationError Something
Run Code Online (Sandbox Code Playgroud)
问题是,由于DomainError
生活在另一个包中,我不能简单地扩展我的ApplicationError
特征:
package com.application.person
sealed trait ApplicationError
case object PersonNotFound extends ApplicationError
case object UnexpectedFatalError extends ApplicationError
// and a function f :: Either ApplicationError Something
Run Code Online (Sandbox Code Playgroud)
我可以创建另一个case object
来包装DomainError
:
sealed trait ApplicationError
// n list of errors, and then:
final case class WrappedDomainError(d: DomainError) extends ApplicationError
Run Code Online (Sandbox Code Playgroud)
但该解决方案充其量只是次优。
另外,如果我想在我的doSomething()
and 中更具体,而不是返回整个DomainError
,而是返回一个不同的子集,该怎么办?
sealed trait ApplicationError extends DomainError // compilation error
Run Code Online (Sandbox Code Playgroud)
我必须考虑每个域层功能中的所有情况。
有什么方法可以在 Scala 中做正确的求和类型吗?
谢谢
TBH,将域错误包装在应用程序错误中并不是一个坏主意。这就是我在你的情况下会做的事情。还有几个选项需要考虑:
让你的 DomainError 和 ApplicationError 扩展一个常见的超类型 Error、CommonError、Failure 等。我个人的偏好是扩展 Throwable - 这样你的错误 AST 就可以变得与异常同构,这可以出于 Java 互操作的原因派上用场。
错误通道也由联合体组成。你的最终类型看起来有点像Either[ApplicationError Either DomainError, A]
。它有点拗口,但你可以通过引入别名让它看起来不那么难看。
type Result[+A] = Either[ApplicationError Either DomainError, A]
def doSomething: Result[???]
Run Code Online (Sandbox Code Playgroud)
sealed trait Result[+A]
case class Success[A](a: A) extends Result[A]
case class ApplicationErr(err: ApplicationError) extends Result[Nothing]
case class DomainErr[A](err: DomainErr) extends Result[Nothing]
def doSomething: Result[???]
Run Code Online (Sandbox Code Playgroud)
val maybeDomainErrorVal: Either[DomainError, ???] = ???
val maybeApplicationErrorVal: Either[ApplicationError, ???] =
maybeDomainErrorVal.leftMap {
case NoPermission => UnexpectedFatalError
}
Run Code Online (Sandbox Code Playgroud)