Scala 当对其中一个项的检查返回false时,结束for-comprehension循环

Scala 当对其中一个项的检查返回false时,结束for-comprehension循环,scala,for-comprehension,Scala,For Comprehension,我对Scala有点陌生,所以如果这件事有点琐碎,我深表歉意 我有一个项目列表,我想反复浏览。我需要对每个项执行检查,如果其中只有一项失败,我希望整个函数返回false。所以你可以把这看作是一个和条件。我希望它被惰性地评估,即当我遇到第一个false返回false时 我习惯了for-yield语法,它过滤通过某个生成器生成的项目(项目列表、序列等)。然而,在我的例子中,我只想中断并返回false,而不执行循环的其余部分。在普通Java中,只需执行返回false在循环中 以一种低效的方式(即当我遇到

我对Scala有点陌生,所以如果这件事有点琐碎,我深表歉意

我有一个项目列表,我想反复浏览。我需要对每个项执行检查,如果其中只有一项失败,我希望整个函数返回false。所以你可以把这看作是一个和条件。我希望它被惰性地评估,即当我遇到第一个false返回false时

我习惯了
for-yield
语法,它过滤通过某个生成器生成的项目(项目列表、序列等)。然而,在我的例子中,我只想中断并返回false,而不执行循环的其余部分。在普通Java中,只需执行
返回false在循环中

以一种低效的方式(即当我遇到第一个错误项时不停止),我可以做到:

   (for {
          item <- items
          if !satisfiesCondition(item)
        } yield item).isEmpty
(用于{

使用Scala中的
forall
()

您的解决方案已重写:

items.forall(satisfiesCondition)
要演示短路,请执行以下操作:

List(1,2,3,4,5,6).forall { x => println(x); x < 3 }
1
2
3
res1: Boolean = false

Scala对于理解的定义不是一般的迭代,这意味着它们不能产生迭代中可能产生的所有结果,例如,你想做的事情

当您返回一个值(即使用
yield
)时,Scala for comprehension可以做三件事。在最基本的情况下,它可以做到这一点:

  • 给定
    M[A]
    类型的对象和
    A=>B
    函数(即,当给定
    A
    类型的对象时,返回
    B
    类型的对象),返回
    M[B]
    类型的对象
例如,给定一个字符序列,
Seq[Char]
,获取该字符的UTF-16整数:

val codes = for (char <- "A String") yield char.toInt
在本例中,我们有类型为
Seq[Char]
Seq[Int]
的对象,以及一个函数
(Char,Int)=>String
,因此我们返回一个
Seq[String]

理解的第三个也是最后一个功能是:

  • 给定类型为
    M[A]
    的对象,使得类型为
    M[T]
    的任何类型
    T
    、函数
    A=>B
    和条件
    A=>Boolean
    ,根据条件返回零或
    M[B]
    类型的对象
这一个更难理解,尽管它一开始看起来很简单。让我们先看看一些看起来很简单的东西,比如,在一系列字符中查找所有元音:

def vowels(s: String) = for {
  letter <- s
  if Set('a', 'e', 'i', 'o', 'u') contains letter.toLower
} yield letter.toLower

val aStringVowels = vowels("A String")
如果用户未登录,我们将获得
None
,否则我们将获得
Some(user)
,其中
user
是包含发出请求的用户信息的数据结构。然后,我们可以像这样对该操作建模:

val coords = for {
  column <- 'A' to 'L'
  row    <- 1 to 10
} yield s"$column$row"
def adminJs(req; HttpRequest): Option[String] = for {
  user <- getUser(req)
  if user.isAdmin
} yield adminScriptForUser(user)
还要注意的是,这称为“for循环”,而不是“for comprehension”,因为它不返回值(它返回
Unit
),因为它没有
yield
关键字


您可以在本文中阅读更多关于real generic iteration的信息,这是一个Scala实验,使用了本文中以相同名称描述的概念。

forall
无疑是特定场景的最佳选择,但为了便于说明,这里有一个很好的旧递归:

@tailrec def hasEven(xs: List[Int]): Boolean = xs match {
  case head :: tail if head % 2 == 0 => true
  case Nil  => false
  case _ => hasEven(xs.tail)
}

我倾向于在循环中大量使用递归,并对不涉及集合的用例进行短路。

在循环过程中,是否需要对项目执行任何操作?如果不需要,则.@krivachy.akos感谢。这是懒惰吗?你说的懒惰是什么意思?它会在第一个错误处停止,这正是你指定的。请在REPL:
Li中尝试一下st(1,2,3,4,5,6).forall{x=>println(x);x<3}
@jbx它实际上被称为短路,而不是懒惰的评估
对于所有
存在
对于收益
是不相似的
对于
@Yury对不起,我不明白你的评论,你能澄清一下吗?我从来没有说过
对于所有
存在
对于收益
是相同的
>或者为
添加一个
。如果您能详细说明,这将有所帮助。@krivachy.akos感谢您添加了exists部分。这对于实现或检查是否有任何项(而不是所有项)满足条件非常有用.非常感谢您提供的所有详细信息。我想我将不得不回到这里,因为您提供了大量信息。
def adminJs(req; HttpRequest): Option[String] = for {
  user <- getUser(req)
  if user.isAdmin
} yield adminScriptForUser(user)
def hasEven(xs: List[Int]): Boolean = {
  for (x <- xs) if (x % 2 == 0) return true
  false
}
@tailrec def hasEven(xs: List[Int]): Boolean = xs match {
  case head :: tail if head % 2 == 0 => true
  case Nil  => false
  case _ => hasEven(xs.tail)
}