0

我有一个条件的嵌套块、一个 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循环不会退出。我也尝试过,但这不起作用,因为它应该返回元组,而不仅仅是退出循环。getTuplebreakfor

我怎样才能让它工作?

4

5 回答 5

3

getTuple 应该评估为 a 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
}

希望这可以帮助

于 2013-02-26T10:26:27.043 回答
3

我建议使用 Scala 的更多功能特性,而不是处理循环和异常。

假设我们有一个函数在某些输入上抛出异常:

def myfn(x: Double): Double =
  if (x < 0)
    throw new Exception;
  else
    Math.sqrt(x);

我们可以将其重构为 return 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不必要地调用所有元素,而不仅仅是我们需要找到第一个成功结果的那些元素——流使计算变得惰性

(另一种选择是使用views,例如

testseq.view.map(optMyfn _).collectFirst({ case Some(x) => x })

.)

于 2013-02-26T11:49:08.867 回答
1

这个电话在声明sys.exit中有点放错了地方。if如果 try 成功,它应该在catch子句中以允许返回 tupe。

于 2013-02-26T10:12:40.437 回答
1

如果你想循环直到你得到一个工作元组,while循环更有意义。for 循环的语义是评估您正在迭代的所有元素的主体。由于您的目标是在满足条件的第一个之后停止,因此 while 循环似乎更自然。当然还有一些功能更强大的替代方案,例如:

  • 将您包装getTuple在一个 中Option,其中None对应于一个异常。
  • 将调用getTuple放在一些可迭代/可遍历的集合中
  • 获取不是的第一个元素None

当我解释这个概念时,Romain Sertelon举了一个很好的例子来说明这个想法......

于 2013-02-26T10:20:40.610 回答
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 的基础知识,但目前这行得通。

感谢您的回答。

于 2013-02-26T11:58:49.957 回答