我有一个嵌套的条件块,一个for循环和try / catch块来返回一个元组:
val (a, b) = {
if (...) {
for (...) {
try {
getTuple(conf)
} catch {
case e: Throwable => println(...)
}
}
sys.exit
} else {
try {
getTuple(userConf)
} catch {
case e: Throwable => println(...); sys.exit
}
}
}
如果if
条件匹配,我想尝试x个不同的conf
配置。当getTuple
抛出异常时,请尝试下一个异常。当getTuple
没有抛出异常时,请使用结果填充元组。 getTuple
返回元组(a,b)
。
问题:但是,当for
不抛出异常时,getTuple
循环不会退出。我也尝试了break
,但这不起作用,因为它应该返回元组而不是退出for
循环。
我怎样才能让它发挥作用?
答案 0 :(得分:3)
getTuple应该评估为Option[Tuple2[T,U]]
,而不是抛出异常,它具有更多含义并且不会破坏程序的流程。
通过这种方式,您可以拥有这样的内容:
val tuples: List[Option[Tuple2[T,U]] = for {
c <- configs
} yield getTuple(c)
val firstWorkingConfig: Option[Tuples2[T,U]] = tuples.flatten.headOption
// Exit the program if no config is okay
firstWorkingConfig.getOrElse {
sys.exit
}
希望这有帮助
答案 1 :(得分:2)
我建议使用Scala的更多功能特性,而不是处理循环和异常。
假设我们有一个在某些输入上抛出异常的函数:
def myfn(x: Double): Double =
if (x < 0)
throw new Exception;
else
Math.sqrt(x);
我们可以重构它以返回Option
:
def optMyfn(x: Double): Option[Double] =
if (x < 0)
None;
else
Some(Math.sqrt(x));
或者,如果我们不想(或不能修改原始代码),我们可以使用Exception.Catcher
简单地包装它:
def optMyfn(x: Double): Option[Double]
= scala.util.control.Exception.allCatch.opt(myfn(x));
现在让我们有一系列数字,我们想找到函数成功的第一个数字:
val testseq: Seq[Double] = Seq(-3.0, -2.0, 2.0, 4.0, 5.0);
我们可以使用Scala的功能特性将函数应用于所有元素,并找到第一个Some
结果
testseq.toStream.map(optMyfn _).flatten.headOption
在不使用toStream
的情况下也可以正常工作,但我们会在所有元素上不必要地调用optMyfn
,而不仅仅是我们需要找到第一个成功结果的那些 - 流进行计算lazy
(另一种选择是使用views,例如
testseq.view.map(optMyfn _).collectFirst({ case Some(x) => x })
)
答案 2 :(得分:1)
sys.exit
语句中的if
调用有点错位。如果尝试成功,它应该在catch
子句内,以允许返回tupe。
答案 3 :(得分:1)
如果你想循环直到你得到一个工作元组,while
循环更有意义。 for循环的语义是为正在迭代的所有元素评估正文。因为你的目标是在满足条件的第一个之后停止,所以while循环似乎更自然。当然会有更多功能性替代品,例如:
getTuple
包裹在Option
中,其中None
对应于例外。getTuple
置于某个可迭代/可遍历的集合中None
在我解释这个概念时,Romain Sertelon给出了一个很好的例子......
答案 4 :(得分:0)
另一个解决方案是将整个块包装到一个方法中并使用return:
val (a: Type, b: Type) = setup(...)
def setup(...) : (Type, Type) = {
if (...) {
for (...) {
try {
return getTuple(...)
} catch {
...
}
}
sys.exit
} else {
try {
return getTuple(...)
} catch {
case e: Throwable => println(...); sys.exit
}
}
}
我想我应该学习更多Scala的基础知识,但现在可以使用。
感谢您的回答。