使用 Try 在 Scala 中处理错误的最佳实践

Man*_*oid 1 scala

我处理异常如下:

def calculate(input: Option[Double]): Try[String] =
  Try {
    input match {
      case (Some(value)) => value.toString
      case (None) => throw new IllegalArgumentException("No value found")
    }
}
Run Code Online (Sandbox Code Playgroud)

在客户端代码中:

val result = calculate(....)

result match {
    case Success(i) => println(i)
    case Failure(s) => throw s // or log(s) to log the issue and continue
}
Run Code Online (Sandbox Code Playgroud)

对于干净优雅的代码库,它是足够好的实践还是可以做得更好?

Iva*_*nko 7

Try通常用于覆盖可能引发错误的部分,例如在您使用某些 Java 库时可能引发异常的情况。但是,如果您想返回可能的错误并强制客户端处理它,这Either[A, B]是更好的选择,至少因为您可以指定更精确的错误类型Left[A]并安全地对您的A类型进行模式匹配,而不是进行可能不正确的模式匹配一些Throwable,就像你会为Failure(t).

因此,在您的情况下,可能的解决方案如下:

sealed trait CalculationError
case class Error1(cause: String) extends CalculationError

def calculate(input: Option[Double]): Either[CalculationError, String] =
    input match {
      case (Some(value)) => Right(value.toString)
      case (None) => Left(Error1("No value found"))
    }
}

val result = calculate(....)

result match {
    case Right(i) => println(i)
    case Left(Error1(s)) => println(s)
}

Run Code Online (Sandbox Code Playgroud)

这是更安全的方法,因为您稍后可以添加另一种类型的错误,例如case class Error2(cause: String) extends CalculationError在客户端模式匹配代码部分,编译将显示一条警告消息,您错过了新错误的处理:Match is not exhaustive。如果Failure(t)编译将无法提示此类警告,因此在错误处理方面更容易出错。

希望这可以帮助!

  • `Option#toRight` 可能会缩短它,如下所示: `input.map(_.toString).toRight(Error1("No value found"))` (2认同)