【问题标题】:for expressions versus foreach in ScalaScala 中的 for 表达式与 foreach
【发布时间】:2011-05-26 20:47:34
【问题描述】:

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

就控制流而言,我不太确定该怎么做:在 Python 中,我们使用 for x in some_iterable 到死,我们喜欢它。在 Scala 中存在一个非常相似的结构,Odersky 将其称为 for 表达式,可能是为了将其与 Java 的 for 循环区分开来。此外,Scala 有一个用于可迭代数据类型的 foreach 属性(我想这将是一个属性,我对 Scala 的了解不够,无法正确命名它)。不过,我似乎无法使用 foreach 为容器中的每个项目调用一个函数。

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

我希望我没有过于模棱两可或过于宽泛,但我只是想了解 Scala 中的一些设计/语言基础知识(目前看来这很酷)。

【问题讨论】:

    标签: scala loops foreach


    【解决方案1】:

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

    这是蟒蛇

    >>> 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> 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 &lt;- gen1 if expr1; v2 &lt;- 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 &lt;- gen1 也确实执行了匹配 case v1 =&gt; 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) 的事实看出!

    【讨论】:

    • 这确实是一个很好的答案。我很高兴我等了几个小时才接受任何东西。
    【解决方案2】:

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

    为了更好地理解 Scala 的理解,请参阅 this question。特别是,您会看到for (x &lt;- xs) f(x) 与xs.foreach(x =&gt; f(x)) 是一回事。

    现在,您提到您似乎不太使用 foreach 方法,但我要指出,几乎所有 Scala 集合的方法都(或可以)仅使用 foreach 实现。请参阅Traversable 的文档——它的所有方法都可以仅使用foreach 来实现。

    请注意,Scala 的 yield 与 Python 的 yield 没有相似之处——您也可以查看 that 问题。

    【讨论】:

      【解决方案3】:

      凭借对嵌套迭代、过滤器和转换的支持,我想说 Scala 的 for 是该语言的优势之一并且非常重要。我倾向于使用 foreach、map 和 filter。

      【讨论】:

        【解决方案4】:

        foreach 是一种函数式风格,而 for 是一种命令式风格。如果您曾经做过任何 lisp 或方案,那么您已经熟悉函数式编程。如果你没有,那么一开始可能会有点混乱。我要做的第一件事是阅读闭包语法,它们是你传递给 foreach 之类的匿名函数。一旦你明白这一切都会变得更有意义。

        【讨论】:

          【解决方案5】:

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

          Scala's For Comprehensions

          Scala Yield

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

          【讨论】:

            猜你喜欢
            • 2019-08-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-01-01
            • 1970-01-01
            • 2017-10-17
            • 2018-02-20
            相关资源
            最近更新 更多