Scala - 嵌套迭代(Odersky 等人,2010 年)
Scala - Nested Iteration (Odersky et al., 2010)
以下代码来自 Odersky 等人。 (第 167 页)于 "Programming in 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.*")
没有它代码将无法编译,因为 "the Scala compiler will not infer semi-colons while inside parentheses"(同上,第 167 页)。 问题一:为什么代码不等同于:
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条件后有分号?有什么作用?
问题 1 的答案 -
for comprehension 在其第一个语句中始终以 <- 开头,该语句为后面的其余表达式创建上下文。
理解中的所有 <-
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)
不在理解之内,而是在 if 表达式之内。所以它不会编译。
问题 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。它更优雅地解释了理解。
您的 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)
用大括号括起代码块 { ... }
允许您跳过显式分号的要求。
以下代码来自 Odersky 等人。 (第 167 页)于 "Programming in 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.*")
没有它代码将无法编译,因为 "the Scala compiler will not infer semi-colons while inside parentheses"(同上,第 167 页)。 问题一:为什么代码不等同于:
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条件后有分号?有什么作用?
问题 1 的答案 -
for comprehension 在其第一个语句中始终以 <- 开头,该语句为后面的其余表达式创建上下文。
理解中的所有
<-
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)
不在理解之内,而是在 if 表达式之内。所以它不会编译。
问题 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。它更优雅地解释了理解。
您的 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)
用大括号括起代码块 { ... }
允许您跳过显式分号的要求。