假设我有一个函数foo
def foo(a: A): B = ...
该功能可能会因以下错误之一而失败:FooError1
,FooError2
和FooError3
。
假设我不想要例外。因此,我定义了一个基本错误类FooError
,其中包含一些派生错误类,并从Either[FooError, B]
返回foo
。
case class FooError(a: A)
case class FooError1(override a: A) extends FooError(a)
case class FooError2(override a: A) extends FooError(a)
case class FooError3(override a: A) extends FooError(a)
def foo(a: A): Either[FooError, B] = ...
有意义吗?
每个函数看起来代码太多了。可以简化吗?
答案 0 :(得分:2)
我认为这值得使用Try
:
type A = Int
type B = String
class FooError(val a: A) extends Throwable
class FooError1(a: A) extends FooError(a)
class FooError2(a: A) extends FooError(a)
class FooError3(a: A) extends FooError(a)
def foo(a: A): Try[B] = {
val r = scala.util.Random
val i = r.nextInt(20)
Try {
i match {
case it if (1 to 3).contains(i) => throw new FooError1(1)
case it if (4 to 6).contains(i) => throw new FooError2(1)
case it if (7 to 9).contains(i) => throw new FooError3(1)
case _ => "value" + a
}
}
} //> foo: (a: playground.A)scala.util.Try[playground.B]
(1 to 5) foreach { x =>
foo(x) match {
case Success(x) => println(x)
case Failure(t) => // error ignored
} //> value1
//| value4
//| value5
}
事实上,你可以取消所有这些类,并简单地抛出一个带有错误代码的异常类型。
type A = Int
type B = String
case class FooError(val a: A) extends Throwable
def foo(a: A): Try[B] = {
val r = scala.util.Random
val i = r.nextInt(20)
Try {
i match {
case it if (1 to 3).contains(i) => throw new FooError(1)
case it if (4 to 6).contains(i) => throw new FooError(2)
case it if (7 to 9).contains(i) => throw new FooError(3)
case _ => "value" + a
}
}
} //> foo: (a: play.A)scala.util.Try[play.B]
(1 to 5) foreach { x =>
foo(x) match {
case Success(x) => println(x)
case Failure(t) => t match {
case FooError(code) => println("Error code was "+code)
}
} //> Error code was 1
//| value2
//| Error code was 2
//| value4
//| value5
}
答案 1 :(得分:1)
您应该将case class FooError(a: A)
替换为sealed trait FooError(a:A)
。
通过这种方式,您可以轻松使用match
表达式,编译器会告诉您是否遗漏了案例。
答案 2 :(得分:1)
我之前见过这个:
import language._
import util._
package object either {
type Ok = Int
type Result = Either[Error, Ok]
implicit def badResult(e: Error): Result = Left(e)
implicit def okResult(i: Ok): Result = Right(i)
}
package either {
sealed trait Error { def info: String }
case class BadInfo(info: String) extends Error
class Typical {
def f(): Result = BadInfo("oops")
def g(): Result = 7
}
}