以下功能有一般或特定错误。
scala> trait Error
defined trait Error
scala> case object General extends Error
defined object General
scala> trait FooError extends Error
defined trait FooError
scala> case object FooError42 extends FooError
defined object FooError42
然后,有两个功能:
scala> def f: Either[Error, Int] = Right(42)
f: Either[Error,Int]
scala> def h: Either[FooError, Int] = Right(55)
h: Either[FooError,Int]
最后,我们可以使用for-understanding来链接它们:
scala> for {
| a <- f.right
| b <- g.right
| } yield b
res3: scala.util.Either[Error,Int] = Left(FooError42)
在这种情况下,Left
的返回类型为Error
,因为Error
可能会出现FooError
或Left
。有必要使用Error
,因为此类型可以表达Error
或FooError
孩子的孩子。
进一步将Error
专门化为FooError
是否有用,即使for-comprehension
返回Either[Error, Int]
。
换句话说,即使trait
未使用直接,创建Error
的孩子FooError
是否有用?
答案 0 :(得分:1)
在你琐碎的例子中,FooError
似乎是多余的。特别是,
它不清楚为什么General
与可能扩展FooError
的各种其他对象/类有意义地不同。所以我从设计中消除了后者。
一旦你有一些有元数据的错误(比如错误代码),但有一些没有,你会更有意义,你需要以不同的方式处理这两种情况。然后,您可以将前者收集到特征中并在特征中声明错误代码:
trait FooError extends Error {
def rc: Int
}
object FooError42 extends FooError {
val rc = 42
}
然而,通过将特征转化为抽象或案例类,可以更好地处理大量的样板,如下所示:
trait Error
object General extends Error
case class FooError (rc: Int) extends Error
object FooError42 extends FooError(42)
object NotFoundError extends FooError(404)
然后使用案例类也可以使模式匹配代码更简单:
def report(e: Error): String = e match {
case FooError(rc) => "HTTP error " + rc
case General => "Complete and utter failure"
}