执行提前终止的函数列表

时间:2015-03-13 21:07:49

标签: scala

我有以下需要按顺序执行的功能列表。

val steps: List[() => StepResult] = List(step1 _, step2 _, step3 _)

每个步骤都将返回一个包含布尔状态的StepResult和一条消息:

case class StepResult(success: Boolean, message: String)

我们的想法是按顺序执行每个步骤,但如果任何步骤失败,请停止查看列表。这样做的最佳方式是什么?

我可以检查每一步,并执行它:

val results = steps.map { step => step() }

但是如果任何步骤失败,我都会错过停止的部分。理想情况下,我应该以{{1​​}}结束,然后我可以检查。

2 个答案:

答案 0 :(得分:4)

您可以使用视图运行maptakeWhile而无需在列表中重复两次:

steps.view.map(_()).takeWhile(_.success).force

视图懒惰地评估,并且当你想要在集合上调用多个方法但只迭代一次,或者只评估其内容一次时,它们非常方便。详细了解他们here。您可以通过调用toIteratortoStream而不是view来完成类似的功能,因为这些集合的运作方式类似。

例如:

val step1 = () => { println("running step1"); StepResult(true, "") }
val step2 = () => { println("running step2"); StepResult(true, "") }
val step3 = () => { println("running step3"); StepResult(false, "") }
val step4 = () => { println("running step4"); StepResult(true, "") }
val steps = List(step1, step2, step3, step4)
steps.view.map(s => s()).takeWhile(_.success).force

这将打印

running step1
running step2
running step3

请注意,running step4未打印,因为在使用view时,maptakeWhile会在单个循环中使用。将其与天真的版本进行对比:

steps.map(s => s()).takeWhile(_.success).toList

由于这不使用view,它将运行所有4个步骤,并打印第四个语句。

如果这是一种方法,您还可以将foldLeft与非本地return一起使用:

def getResults(steps: Seq[() => StepResult]): Seq[StepResult] = 
    (Seq.empty[StepResult] /: steps) { case (soFar, next) =>
        val nextRes = next()
        if (nextRes.success) {
            soFar :+ nextRes
        } else return soFar
}

或递归地,正如Ryan的回答所解释的那样。

答案 1 :(得分:1)

您可以使用递归:

def doIt(steps: List[() => StepResult]): List[StepResult] = steps match {
  case Nil => Nil
  case head :: tail => 
    val result = head()
    if (result.success)
      result :: doIt(tail)
    else
      result :: Nil
}