以下代码来自Odersky等人。 (第167页)" Scala编程"。
val filesHere = (new java.io.File(".")).listFiles
def fileLines(file: java.io.File) =
scala.io.Source.fromFile(file).getLines().toList
def grep(pattern: String) =
for (
file <- filesHere
if file.getName.endsWith(".scala");
line <- fileLines(file)
if line.trim.matches(pattern)
) println(file +": "+ line.trim)
grep(".*gcd.*")
如果没有它,代码将无法编译,因为&#34; Scala编译器在括号内不会推断出半冒号&#34; (同上,第167页)。 问题1:为什么代码不等同于:
def grep(pattern: String) =
for (
file <- filesHere
if (file.getName.endsWith(".scala")){
line <- fileLines(file)
}
if line.trim.matches(pattern)
) println(file +": "+ line.trim)
grep(".*gcd.*")
问题2:为什么在上面的代码中需要第一个if条件之后的分号?它起什么作用?
答案 0 :(得分:2)
回答问题1 -
for comprehension应该始终以&lt; - 开头,它的第一个语句为后面的剩余表达式创建上下文。
理解中的所有<-
flatMap
期望最后一个map
。全部如果filter
。
例如
for (
file <- filesHere
if file.getName.endsWith(".scala")
contents <- file.getContents
) yield (contents)
这相当于fileHere.flatMap(file).filter(_.endsWith(".scala")).map(_.getContents)
<-
表达式都应直接用于理解。您可以编写嵌套用于理解。 line <- fileLines(file)
不在理解之内,而在于表达式。所以它不会编译。回答问题2-
if
或scala中的任何表达式
以下代码有效
val filesHere = (new java.io.File(".")).listFiles
def fileLines(file: java.io.File) =
scala.io.Source.fromFile(file).getLines().toList
def grep1(pattern: String) = for {
file <- filesHere
if file.getName.endsWith(".scala")
line <- fileLines(file)
if line.trim.matches(pattern)
} println(file +": "+ line.trim)
我推荐这个tutorial。它更加优雅地解释了理解。
答案 1 :(得分:1)
你的for循环有几个generators和过滤器:
for (
file <- filesHere // generator
if file.getName.endsWith(".scala"); // filter
line <- fileLines(file) // generator
if line.trim.matches(pattern) // filter
) println(file + ": " + line.trim)
在Scala中,生成器和相应的过滤器可以放在for comprehension
中。这个link可能会提供有关该主题的更多详细信息。
对于分号,它需要与编译器所说的完全一样:the Scala compiler will not infer semi-colons while inside parentheses
。
你的for循环与以下内容没有区别:
for (
file <- filesHere if file.getName.endsWith(".scala");
line <- fileLines(file) if line.trim.matches(pattern)
) println(file + ": " + line.trim)
使用大括号{ ... }
括起代码块可以跳过显式分号的要求。