78

给定一个选项,获取其值或尝试抛出异常的惯用方法是什么?

def foo() : String = {
  val x : Option[String] = ...
  x.getOrException()
}
4

5 回答 5

136

throw语句”实际上是 Scala 中的表达式,它具有 type Nothing,它是所有其他类型的子类型。这意味着您可以只使用普通的 old getOrElse

def myGet[A](oa: Option[A]) = oa.getOrElse(throw new RuntimeException("Can't."))

不过,你真的,真的不应该这样做。

于 2013-04-28T14:03:19.943 回答
51

(编辑:这不是最好或最惯用的方法。我在不熟悉 Scala 时写了它。我把它留在这里作为如何这样做的例子。现在我会像 @TravisBrown 那样做)

我认为这实际上归结为两件事:

  • 你有多确定价值是存在的?
  • 如果不是,你想如何反应?

如果在你的代码中你期望值在那里,并且在远程情况下你不希望你的程序快速失败,那么我只会做一个正常的get,让 Scala 抛出一个NoSuchElementException如果没有价值:

def foo() : 字符串 = {
  val x : 选项 [字符串] = ...
  x.get
}

如果您想以不同的方式处理此案(抛出您自己的异常),我认为更优雅的方式如下所示:

def foo(): 字符串 = {
  val x: 选项 [字符串] = 无
  x匹配{
    案例一些(价值)=>价值
    case None => throw new MyRuntimeException("blah")
  }
}

Option当然,如果您想为None您将使用的情况提供自己的替代值getOrElse

def foo(): 字符串 = {
  val x: 选项 [字符串] = 无
  x.getOrElse("我的替代值")
}
于 2013-04-29T09:18:53.097 回答
13

只需使用 .get 方法。

def get[T](o:Option[T]) = o.get

如果 o 是 None 的实例,它将抛出 NoSuchElementException。

基本上,我会使用这样的选项:

def addPrint(oi:Option[Int]) = oi.map(_+1).foreach(println)
addPrint(Some(41))
addPrint(Some(1336))
addPrint(None)

以避免您的具体问题。

于 2013-04-28T14:05:33.487 回答
11

我希望这将帮助您了解如何使用类型来表示错误(以及通常的影响)。

函数式 Scala 中的错误处理策略

  • 用于Option返回可选值。例如- 无法在存储中找到实​​体。

  • 用于Option(possiblyNull)避免Some(null).

  • 用于Either[Error, T]报告预期的失败。 例如- 电子邮件格式错误,无法将字符串解析为数字等。

  • 将您的错误建模为ADT(简单地说是类型层次结构)以使用它,例如,在 Either 的左侧来表示更复杂的错误场景。

  • throwException仅用于表示意外且不可恢复的故障。就像缺少配置文件一样。

  • 使用Either.catchOnlyor Tryor Cats.IO(高级)而不是 catch 块来处理意外故障。提示:您仍然可以使用 ADT,但可以从 throwables扩展它们。更多关于EithervsTry

  • 使用ValidatedCats lib 中的数据类型而不是快速失败 ( Either) 来累积错误,但更喜欢模块级别的 Either 以简化程序的组合(以具有相同的类型)。例如——表单数据验证、解析错误累积。

  • 使用提到的类型并且不要抢先优化程序- 因为很可能瓶颈出现在业务逻辑中,而不是在效果类型中。

这种方法将简化代码的维护和更新,因为您无需了解实现细节(也称为本地推理)即可对其进行推理。此外 - 减少错误 - 您不能错过类型中的错误。并且更容易编写程序(在map,flatMap和其他组合器的帮助下) - 因为它在类型级别上更简单,而不是非本地异常和副作用。
更多关于学习函数式 Scala 的信息。


但请注意,有时使用这种方法,类型可能会堆积起来,并且可能会变得更难组合。例如,给定:x: Future[Either[Error, Option[T]]]你可以做什么:

  • 使用mapflatMap结合模式匹配来组成这些类型的不同值,例如:
x.faltMap { case Right(Some(v)) => anotherFuture(v); case Left(er) => ... }


最后,在您的情况下,一种选择是:

def foo() : Either[Error, String] = {
    val x : Option[String] = ...
    x match {
        case Some(v) => Right(v)
        case None => Left(Error(reason))
    }
}
于 2016-03-02T00:19:17.020 回答
1

Scala 现在支持使用getOrElse()方法在地图上进行此操作,请参阅此处的文档

正如已经指出的,在 Scala 中抛出异常也是一个表达式。

因此,您可以执行以下操作:

myMap.getOrElse(myKey, throw new MyCustomException("Custom Message HERE")
于 2018-08-21T10:05:02.503 回答