Scala风格:用于vs foreach,过滤器,地图等

时间:2013-09-18 16:19:07

标签: scala coding-style

对于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)我发现有很多文章/帖子说服用于理解,我觉得使用它并不方便。恕我直言,内部迭代非常易读。

有关此主题的最佳指南是什么?

2 个答案:

答案 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 - 理解(帖子的原始主题)是flatMapmapfilter的组合。如果您正在做一些相当简单的事情,那么这两个版本都将具有可读性,但如果您正在进行长链flatMapmapfilter串联起来创建一个复杂的转换,然后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实际上是mapfilter的语法糖。