从嵌套条件返回,for循环,在Scala中尝试/ catch块

时间:2013-02-26 09:58:02

标签: scala for-loop nested return try-catch

我有一个嵌套的条件块,一个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循环。

我怎样才能让它发挥作用?

5 个答案:

答案 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的基础知识,但现在可以使用。

感谢您的回答。