Scala中的错误处理

时间:2014-02-01 08:19:57

标签: scala error-handling functional-programming

假设我有一个函数foo

def foo(a: A): B = ... 

该功能可能会因以下错误之一而失败:FooError1FooError2FooError3

假设我不想要例外。因此,我定义了一个基本错误类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] = ...

有意义吗?

每个函数看起来代码太多了。可以简化吗?

3 个答案:

答案 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
  }
}