【问题标题】:Scala - difference between for each loopsScala - 每个循环之间的区别
【发布时间】:2013-05-20 14:03:54
【问题描述】:

以下两种说法有区别吗?他们达到了同样的目的,对吗?它们是否编译为相同的 Java 代码?它们之间是否存在任何性能差异,或者仅仅是偏好/可读性问题?

for (thing <- things) {
    doSome(thing)
}

things.foreach(
  thing =>
    doSome(thing)
)

【问题讨论】:

  • 好问题。我想知道for 是否能够对特定(例如数组)类型应用任何优化。检查 scala -print,如果没有显示任何差异,则检查字节码。 (尝试数组和非数组类型。)
  • 另外,第二种形式不是通过 additional 调用为 lambda 创建了一个额外的匿名类型吗?这也是第一种形式的情况还是可以省略另一个函数/方法调用?可能值得将things.foreach(doSome)(或doSome _,如果它恰好是一种方法)放入混合中进行比较..
  • 你知道,你可以同时尝试并比较类文件。
  • @user2246674 这不是针对您的;它针对的是OP,因为没有@标签,所以应该很清楚。与更多关于 SO 的问题相比,更多的用户知道如何独立做更多的事情是 SO 的重点。

标签: scala loops for-loop foreach


【解决方案1】:

scala-lang.org:

与往常一样,for 表达式可以用作涉及 foreach、map、withFilter 和 flatMap 的表达式的替代语法,因此打印迭代器返回的所有元素的另一种方法是:

for (elem

“替代语法”表示相同。

【讨论】:

  • @user2246674 如果您发现其中包含魔鬼的细节,请向负责 scala 文档的团队提交错误报告,因为语言清晰。
  • 链接文档的更新版本可以在新的docs.scala-lang.org 网站上找到:docs.scala-lang.org/overviews/collections/iterators.html
  • 如果您用相同的所有内容(变量名称)编译类并且类将相等,我会感到震惊。我敢打赌会有不同。
  • @AdamGent 然后这样做并作为单独的答案发布。还建议向 scala 团队提交错误报告。
【解决方案2】:

它们是相同的。给定

class Foreach {
  val things = List(1,2,3)
  def doSome(i: Int) { println(i) }
  def one { for (thing <- things) { doSome(thing) } }
  def two { things.foreach{ thing => doSome(thing) } }
}

字节码是

public void one();
  Code:
   0:   aload_0
   1:   invokevirtual   #40; //Method things:()Lscala/collection/immutable/List;
   4:   new #42; //class Foreach$$anonfun$one$1
   7:   dup
   8:   aload_0
   9:   invokespecial   #46; //Method Foreach$$anonfun$one$1."<init>":(LForeach;)V
   12:  invokevirtual   #52; //Method scala/collection/immutable/List.foreach:(Lscala/Function1;)V
   15:  return

public void two();
  Code:
   0:   aload_0
   1:   invokevirtual   #40; //Method things:()Lscala/collection/immutable/List;
   4:   new #55; //class Foreach$$anonfun$two$1
   7:   dup
   8:   aload_0
   9:   invokespecial   #56; //Method Foreach$$anonfun$two$1."<init>":(LForeach;)V
   12:  invokevirtual   #52; //Method scala/collection/immutable/List.foreach:(Lscala/Function1;)V
   15:  return

【讨论】:

  • 谢谢雷克斯,太好了!我很感激。
【解决方案3】:

for 理解被定义为简单的句法翻译。这非常重要,因为这允许 任何 对象与 for 理解一起工作,它只需要实现正确的方法。

IOW:Scala 语言规范说第一个 sn-p 被翻译成第二个。因此,如果两个 sn-ps 之间存在任何任何差异,那将违反规范,因此是一个非常严重的编译器错误。

有些人要求,甚至实施了对某些对象的特殊处理(例如Ranges),但这些补丁总是被拒绝,理由是对特殊类型的特殊处理只会使那些特殊类型受益,而使Scala 速度更快总体而言对每个人都有好处。

请注意,使用宏,可能会检测到,例如,迭代 Range 纯粹作为简单的 C 风格 for 循环并将其转换为 while 循环或直接尾递归内部函数,而无需更改规范或向编译器添加特殊大小写。

【讨论】:

  • 嗨乔格,谢谢!这确实有助于理解为什么两者编译成相同的 Java 代码。我肯定在这里学到了一些东西。 More reading for anyone interested.
【解决方案4】:

基本上

for 循环是一个表示

执行此操作 n。次

foreach 循环是一个表示

对每个值/对象执行此操作

【讨论】:

  • 不是这样。阅读其他答案以更好地理解为什么 for 不是真正的循环(它是“for 理解”),它也可以用于“针对每个值/对象”。
猜你喜欢
  • 1970-01-01
  • 2010-09-06
  • 2021-05-12
  • 1970-01-01
  • 2011-04-07
  • 2017-11-01
  • 2016-07-08
  • 2019-01-11
  • 1970-01-01
相关资源
最近更新 更多