表达式与Scala中的foreach

时间:2010-12-16 23:27:22

标签: scala loops foreach

我正在通过Programming in Scala工作,虽然我很想从Python的角度看问题,但我不想编写“Scala中的Python”。

就控制流而言,我不太清楚要做什么:在Python中,我们使用for x in some_iterable来死,我们喜欢它。 Scala中存在一个非常类似的构造,Odersky称之为表达式,可能是为了将它与Java for循环区分开来。此外,对于可迭代数据类型,Scala具有foreach属性(我猜它将是一个属性,我不太了解Scala的名称)。但是,我似乎不能使用foreach来为容器中的每个项目调用一个函数。

这给我留下了一些问题。首先,表达式是Scala中的重要/大量使用的构造,就像它们在Python中一样;其次,我何时应该使用foreach而不是for表达式(除了在每个项目上调用函数的明显情况之外)容器)?

我希望我不是非常暧昧或过于宽泛,但我只想尝试Scala中的一些设计/语言基础(到目前为止看起来非常酷)。

5 个答案:

答案 0 :(得分:59)

python在列表推导和生成器表达式中使用for。那些非常类似于scala for表达式:

这是python

>>> letters = ['a', 'b', 'c', 'd']
>>> ints = [0, 1, 2, 3]
>>> [l + str(i) for l in letters for i in ints if i % 2 == 0]
['a0', 'a2', 'b0', 'b2', 'c0', 'c2', 'd0', 'd2']

这是scala

scala> val letters = List('a', 'b', 'c', 'd')
scala> val ints = List(0, 1, 2, 3)
scala> for (l <- letters; i <- ints if i % 2 == 0) yield l.toString + i
res0: List[java.lang.String] = List(a0, a2, b0, b2, c0, c2, d0, d2)

每个构造都可以使用多个生成器/迭代器,应用过滤器表达式并生成组合表达式。在python中,(expr for v1 in gen1 if expr1 for v2 in gen2 if expr2)大致相当于:

for v1 in gen1:
  if expr1:
    for v2 in gen2:
      if expr2:
        yield expr

在scala中for (v1 <- gen1 if expr1; v2 <- gen2 if expr2) yield expr大致相当于:

gen1.withFilter(expr1).flatMap(v1 => gen2.withFilter(expr2).map(v2 => expr))

如果您喜欢python for x in xs语法,那么您可能会喜欢scala for表达式。

Scala有一些额外的语法和翻译扭曲。语法明智for可以与大括号一起使用,以便您可以将语句放在单独的行上。您还可以执行值分配。

val res = for {
    i <- 1 to 20; i2 = i*i
    j <- 1 to 20; j2 = j*j
    k <- 1 to 20; k2 = k*k
    if i2 + j2 == k2
  } yield (i, j, k)

此外v1 <- gen1确实执行匹配case v1 => gen1。如果没有匹配,则从迭代中忽略这些元素。

scala> val list = List(Some(1), None, Some(2))
scala> for (Some(i) <- list) yield i
res2: List[Int] = List(1, 2)

我认为for在语言中占有重要地位。我可以从你正在阅读的书中找到关于它的整章(23)!

答案 1 :(得分:25)

是的,Scala用于理解(因为它们是众所周知的)被大量使用,但它们实际上只是特定方法组合的语法糖,许多人更喜欢直接调用这些方法而不是使用语法糖。 / p>

为了更好地理解Scala的理解,请参阅this question。特别是,您会看到for (x <- xs) f(x)xs.foreach(x => f(x))相同。

现在,您提到您似乎没有使用foreach方法,但我会指出几乎所有Scala集合的方法都是(或可以)只用{{1 }}。请参阅foreach的文档 - 其所有方法只能使用Traversable实现。

请注意,Scala的foreach与Python yield没有任何相似之处 - 您也可以查询 that 问题。

答案 2 :(得分:3)

由于支持嵌套迭代,过滤和转换,我认为Scala的for是该语言的优势之一,而且非常重要。我更倾向于使用foreachmapfilter

答案 3 :(得分:3)

foreach是一种功能性风格,而for是一种势在必行的风格。如果您曾经做过任何lisp或方案,那么您已经熟悉了函数式编程。如果你还没有,那么一开始可能会有点混乱。我要做的第一件事是阅读闭包语法,它是你传递给foreach之类的东西的匿名函数。一旦你明白它会更有意义。

答案 4 :(得分:3)

您的问题主要通过以下方式解答:

Scala's For Comprehensions

Scala Yield

总结一下:它主要是风格。就个人而言,我赞成功能方法,但在处理嵌套循环时更喜欢理解的简洁性。