对于smth集合中“高级迭代”的scala中最好的样式是什么。在哪些情况下,我应该使用for-comprehension,当我应该寻找迭代的替代方式(在样式方面)。在Programming in Scala
书中,有一个看起来几乎与下一个相关的例子:
for{
file <- filesHere
if file.getName.endsWith("txt")
line <- Source.fromFile(file).getLines.toList
if line.trim.matches(pattern)
} println("|" + file + ": " + line.trim)
我尝试使用内部迭代重写它并得到:
filesHere foreach { file =>
if (file.getName.endsWith("txt")) {
Source.fromFile(file).getLines.toList foreach {line =>
if (line.trim.matches(pattern)) println("|" + file + ": " + line.trim)
}
}
}
然而,在网络上(包括stackoverflow)我发现有很多文章/帖子说服用于理解,我觉得使用它并不方便。恕我直言,内部迭代非常易读。
有关此主题的最佳指南是什么?
答案 0 :(得分:3)
我认为你学习Scala很棒。它背后有一个很棒的社区,非常活跃,我认为随着时间的推移,你对自己的决定会越来越满意。
目前,至少,我认为你应该坚持“Scala编程”,因为它写得非常好,并且对语言有很好的介绍。然后,一个好看的地方将是Scala api文档本身,因为许多类/方法包含示例代码。此外,谷歌小组非常活跃(并且,正如我所说,那里的人非常友好)。
请记住,您提供的代码作为示例不返回任何值,而是仅提供副作用(在Java中,这将具有void
返回值)。大多数Scala API都围绕着函数,几乎没有副作用返回一个值(例如,你可能有一个记录的副作用,但惯用的scala代码会最小化方法和函数中的副作用)。
在Scala API中,如果符合您的需要,有些方法可以作为首选样式。例如,在Scheme中你可能会做一个内循环来迭代,在Scala中它可能看起来像这样:
val myScores = List(4, 8, 6, 1, 2, 4, 9, 8)
def max(ls: List[Int]): Int = {
def iter(acc: Int, rem: List[Int]): Int = {
if (rem.isEmpty) acc
else if (rem.head > acc) iter(rem.head, rem.tail)
else iter(acc, rem.tail)
}
iter(ls.head, ls)
}
但我不需要编写该函数,因为max
已在列表API中实现:
myScores.max
因此,如果您想要做的事情已经由库实现,那么您应该使用它。 max()
是一个简单的示例,但在Scala API和scalaz
for
- 理解(帖子的原始主题)是flatMap
,map
和filter
的组合。如果您正在做一些相当简单的事情,那么这两个版本都将具有可读性,但如果您正在进行长链flatMap
,map
和filter
串联起来创建一个复杂的转换,然后for
- 理解将更具可读性。
具体到您的问题,我认为for
- 理解版本更容易理解:
val filterMapFlatmapVersion: List[String] =
fileNames.filter(_.endsWith("txt")).flatMap { file =>
io.Source.fromFile(file).getLines().toList.map(_.trim).filter(_ == pattern)
}
val forVersion: List[String] =
for {
fileName <- fileNames
if fileName.endsWith("txt")
line <- io.Source.fromFile(fileName).getLines()
if line.trim().matches(pattern)
} yield line.trim
答案 1 :(得分:1)
我希望for-comprehension是Scala的首选方法。值得注意的是,for-comprehension实际上是map
和filter
的语法糖。