在短路操作中将空 list/Seq 视为失败的惯用(快速)方法是什么?

What is the idiomatic (and fast) way of treating the empty list/Seq as failure in a short-circuiting operation?

我有一种情况,我正在使用函数对规则应用程序进行建模,每个函数返回应用时将采取的操作,或者,如果无法应用规则,则返回空列表。我有许多规则,我想按顺序和短路尝试。在我习惯的其他语言中,我会将空序列视为 false/None 并将它们与 orElse 链接起来,如下所示:


def ruleOne(): Seq[Action] = ???
def ruleTwo(): Seq[Action] = ???
def ruleThree(): Seq[Action] = ???

def applyRules(): Seq[Action] = ruleOne().orElse(ruleTwo).orElse(ruleThree)

但是,据我了解情况,

我可以使用 return,这让我感觉很糟糕,或者更糟糕的是,嵌套的 if 语句。 if let 在这里会很棒,但 AFAICT Scala 没有。

这里的惯用方法是什么?

这里有不同的方法。 其中之一是将所有操作组合在一个 Seq 中(因此创建一个 Seq[Seq[Action]]),然后使用 find(它将 return 匹配给定条件的第一个元素)。所以,例如:

Seq(ruleOne, ruleTwo, ruleThree).find(_.nonEmpty).getOrElse(Seq.empty[Action])

我不清楚你的域应用,但最后的getOrElse允许将find方法产生的Option转换为Seq。这种方法虽然评估了所有序列(没有短路)。

另一种方法是用一种方法来丰富 Seq,该方法模拟了您对 orElse 的想法,使用皮条客我的 library/extensions 方法:

implicit class RichSeq[T](left: Seq[T]) {
   def or(right: => Seq[T]): Seq[T] = if(left.isEmpty) { right } else { left }
}

名称参数启用短路评估。实际上,仅当 左侧序列为空时 才计算右侧序列。

Scala 3 对这种抽象有更好的语法:

extension[T](left: Seq[T]){
  def or(rigth: => Seq[T]): Seq[T] = if(left.nonEmpty) { left } else { rigth }
}

这样可以调用:

ruleOne or ruleTwo or ruleThree

Scastie for scala 2

Scastie for scala 3