我们说我有一个对象A
,它可能有一个Option
B
,它也可能引用另一个可选对象C
(嵌套选项)
我已经看过几种访问C
的方式,比如for-comprehension,模式匹配或flatMap
这些看起来都很好看。但是,如果我必须返回某种错误消息或在B
或C
丢失时抛出异常或提供cannot execute because B is missing
或C not set
等消息,该怎么办?我只能回到(嘲笑):
if(a.b.isDefined)
{
if(a.b.c.isDefined)
{
//do work
}
else throw new Exception1 //or call something other
}
else throw new OtherException //or do something other
我如何以功能或更流畅的方式处理?
答案 0 :(得分:6)
您可以添加一种方法将Option
转换为Try
,如果值为无,则会失败。
implicit class OptionWrapper[T](val o: Option[T]) extends AnyVal {
def tryGet(e: => Throwable): Try[T] = o match {
case Some(x) => Success(x)
case None => Failure(e)
}
}
然后你可以做
a.b.tryGet(new OtherException).flatMap(_.tryGet(new Exception1))
答案 1 :(得分:3)
您可以使用getOrElse[B >: A](default: ⇒ B): B
:
a.b.getOrElse(throw new OtherException).c.getOrElse(throw new Exception1)
使用implicit
包装和AnyVal
优化(之前描述)是个好主意,但您的代码变得不那么可读。我认为更喜欢使用现有方法而不是每次都写包装器。
关于map
,这里真的没用。如果您不需要抛出Exception
,那就有意义了。
答案 2 :(得分:2)
而不是将Option转换为其他东西,我会这样做:
ggplot(dat2, aes(x = variable, y = value)) +
stat_summary(geom = 'point', fun.y = 'mean', size = 2) +
stat_summary(geom = 'errorbar', width = 0.2) +
xlab(NULL) +
theme_bw()
简而言之,如果 b 已定义,那么map将允许您使用它,然后您可以使用 c 上的getOrElse返回它,否则抛出异常。 最后一个getOrElse适用于 b ,所以如果map返回 c 的实例,它将返回它,否则如果 b 未定义它会让你抛出一个异常。
我用Scalatest写了一个快速测试来证明它:
def getC(a: A) = a.b.map { b1 =>
b1.c.getOrElse {
throw new UndefinedC
}
}.getOrElse {
throw new UndefinedB
}
编辑: 顺便说一句,Alexandr Dorokhin的答案比我的答案少,如果你在测试中使用它们就会通过。