我有以下需要按顺序执行的功能列表。
val steps: List[() => StepResult] = List(step1 _, step2 _, step3 _)
每个步骤都将返回一个包含布尔状态的StepResult和一条消息:
case class StepResult(success: Boolean, message: String)
我们的想法是按顺序执行每个步骤,但如果任何步骤失败,请停止查看列表。这样做的最佳方式是什么?
我可以检查每一步,并执行它:
val results = steps.map { step => step() }
但是如果任何步骤失败,我都会错过停止的部分。理想情况下,我应该以{{1}}结束,然后我可以检查。
答案 0 :(得分:4)
您可以使用视图运行map
和takeWhile
而无需在列表中重复两次:
steps.view.map(_()).takeWhile(_.success).force
视图懒惰地评估,并且当你想要在集合上调用多个方法但只迭代一次,或者只评估其内容一次时,它们非常方便。详细了解他们here。您可以通过调用toIterator
或toStream
而不是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
时,map
和takeWhile
会在单个循环中使用。将其与天真的版本进行对比:
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
}