Scala的for推导式和for循环

4

目标

尝试解密for循环和for推导式以及它们之间的区别。

Expr1          ::=  `for' (`(' Enumerators `)' | `{' Enumerators `}')
                       {nl} [`yield'] Expr
Enumerators    ::=  Generator {semi Generator}
Generator      ::=  Pattern1 `<-' Expr {[semi] Guard | semi Pattern1 `=' Expr}
Guard          ::=  `if' PostfixExpr

问题

For循环

枚举值enumsenums生成的每个绑定上,for循环会执行表达式ee。

"执行表达式"意味着for循环不会返回一个结果值,而仅仅是对每个绑定应用一些操作,因此它基本上是一个语句(在我看来,在Scala中,表达式返回一个值,但语句不返回值)?

例如,下面的内容将不会产生任何结果。

val mnemonic = Map('2' -> "ABC", '3' -> "DEF")
val a = for ((digit, str) <- mnemonic) str.contains(digit)

为理解

对于枚举(enums)的for comprehension会生成绑定,评估表达式ee并收集结果。

而For Comprehension将通过收集每个绑定的Expr表达式的评估结果来生成一个集合对象作为结果。那么,创建的集合类型是什么?如果它是一个方法,我可以查看API文档,但是哪个文档指定了For comprehension返回的类型?

2个回答

4

for循环会对集合中的每个元素执行一次语句:

for (x <- List(1,2,3)) {
  println(x)
}

将打印数字1、2和3。循环的返回类型是Unit,类似于Java中的void,因此对其进行任何分配都没有意义。

使用关键字yield的for推导只是mapflatmap的语法糖。这两个语句等效:

val y1 = for (x <- List(1,2,3)) yield x+1
val y2 = List(1,2,3).map(x => x+1)

1
一个有用的补充是,for循环主要用于具有副作用的操作,而for推导通常是纯表达式。 - Samar
1
如果我们不使用yield,那么使用desugaring也是相同的情况,flatMap就会被替换为foreach,而循环体则放在最后一个lambda中。例如:for(x <- List(1,2,3); y <- List(2,3,4)) println(x + y) desugared 为 List(1, 2, 3).foreach(x => List(2, 3, 4).foreach(y => print(x, y))) - Łukasz

1

Scala中的for推导式是mapflatMapfilter的语法糖。它们返回的类型取决于您在推导式中使用的集合类型,因此:

val result1: List[Int] = for (x <- List(1,2,3)) yield x
val result2: String = for (x <- "string") yield x
val result3: Future[Unit] = for (x <- futureReturningFunction()) yield x

1
我认为for表达式可以返回任意输入集合无关的任意集合类型。我们可以在yield表达式中执行操作以返回任何类型的元素。 - Samar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接