使用括号“for”

时间:2013-09-05 04:58:38

标签: scala

我想知道,为什么这段代码不能编译?

val files = (new java.io.File(".")).listFiles
for (file <- files if file.getName.endsWith(".scala")) {
  yield file
}

4 个答案:

答案 0 :(得分:10)

简短的回答是,您的代码包含语法错误,因为 yield 关键字包含在传递给for-comprehension的代码块中。当编译器在 for 之后直接遇到花括号时,它会将其视为副作用的理解,并且不理解 yield 的含义。

对于长篇答案,我们需要更多地了解for-comprehension。

For-comprehensions有许多可能的表达方式,每个看似微小的差异都会彻底改变for-comprehension的行为。

让我们来看看最简单的语法

for(generator1) { code_block }

请注意, generator1 code_block 是符号,不是文字代码。生成器具有以下语法...

identifier <- expression

请注意,任何表达式都不起作用。对于上面的示例语法,表达式必须求值为定义 foreach 方法的某个对象,因为for-comprehension的此语法表示 code_block 应该是副作用代码(即在一些外部作用域中改变一些变量,或者写入数据库,或者其他......),并且for-comprehension本身不应该计算为一个值(事实上,如果你试图将for表达式赋给变量,你得到的值就是Unit)。

在您的情况下,您打算写的是以下,稍微复杂的语法。

for(generator1 guard1) yield { code_block }

在这种语法中,我们引入了一些新的语法元素,并在幕后提出了一些新的要求。首先,让我们分解一下。

和以前一样, guard1 实际上是一个符号,实际的语法实际上看起来更像......

if boolean_expression

当你有一个保护表达式时,这也意味着我们之前为 generator1 所讨论的表达式也必须评估为定义过滤器方法。特别注意我们没有谈到特定的特征/接口/抽象类。 Scala的“for-comprehensions”利用duck typing,因此任何实现您使用的特定语法所需方法的对象都可以在for-comprehension构造中使用。这非常强大。

无论如何,回到我们的新语法,另一个关键区别是 yield 关键字。此关键字对我们的生成器表达式施加了另一个限制,因为现在我们的生成器必须定义 map 方法。但是,这也解除了使用 foreach 方法的限制,因为您不能同时存在 yield 关键字并且不存在于相同的for-understanding中。

在那里使用 yield 关键字,现在的期望是 code_block 是非副作用的代码,而是某种形式的转换。此外,for-comprehension现在评估为一个值(类似于用于生成器的表达式的输出类型)。这是因为,在幕后,for-comprehension实际上只是调用 map

这应该是足够的信息来回答你的问题,但我强烈建议你阅读map / flatmap / foreach和for-comprehensions,因为我在这里没有涉及到更多内容。

答案 1 :(得分:2)

这对你来说如何?

if (flag) {
  // some code
} { else
  // other code
}

else看起来是否在正确的位置?与for-comprehensions一样:yield必须介于第一个括号(或大括号)和正在产生的表达式之间。

答案 2 :(得分:1)

这就是为什么圣经说:

Avoid the temptation to write things like this:

  for (file <- filesHere if file.getName.endsWith(".scala")) {
    yield file  // Syntax error!
  }

chapter and verse,就在this anchor之前。

希望这会有所帮助:for表示foreach后的expr;在for means map之后的yield expr。对SO的影响当然有答案。

答案 3 :(得分:1)

将产量放出大括号

scala> val r = for (file <- files if file.getName.endsWith(".scala")) yield file

r: Array[java.io.File] = Array()

如果需要,您可以在yield之后编写大括号:yield {file}