scala foreach和地图初始化程序

时间:2010-07-10 20:11:10

标签: function scala initializer

刚刚看到一个有趣的可能性来初始化Scala中的代码块以获得高级函数,例如foreach或map:

(1 to 3) map {
  val t = 5
  i => i * 5
}


(1 to 3) foreach {  
  val line = Console.readLine  
  i => println(line)  
}  

这是一些记录的功能还是我应该避免这样的结构?我可以想象,“初始化”块进入构造函数,闭包本身变成了apply()方法吗?

感谢Pat的原始问题(http://extrabright.com/blog/2010/07/10/scala-question-regarding-readline

2 个答案:

答案 0 :(得分:12)

虽然使用的功能并不少见,但我承认这是一个相当奇怪的功能组合。基本技巧是Scala中的任何块都是一个表达式,其类型与块中的最后一个表达式相同。如果最后一个表达式是一个函数,这意味着该块具有函数类型,因此可以用作“map”或“foreach”的参数。在这些情况下发生的情况是,当调用“map”或“foreach”时,将对块进行评估。该块评估函数(在第一种情况下i => i * 5),然后在该范围上映射该函数。

此构造的一种可能用途是块用于定义可变变量,并且结果函数在每次调用变量时都会变量。变量将被初始化一次,由函数关闭,并且每次调用函数时它们的值都会更新。

例如,这是计算前6个阶乘数

的一种有些令人惊讶的方法
(1 to 6) map {
      var total = 1
      i => {total *= i;total}
    } 

(顺便说一句,抱歉以使用阶乘作为例子。它或者是斐波那契。功能性 Progamming Guild规则。你有问题,把它们带到大厅的男孩们身上。)

让块返回函数的一个不那么迫切的原因是在块中更早地定义辅助函数。例如,如果你的第二个例子是

(1 to 3) foreach {  
  def line = Console.readLine  
  i => println(line)  
}

结果是每行读取三行并回显一次,而您的示例读取一行并回显三次。

答案 1 :(得分:1)

首先,原始博客评论“Scala Question Regarding readLine”提及

  

line”是一个值,无法执行,只能从执行“Console.readLine”方法的结果中分配一次。
  关闭时使用次数少于三次   但如果将其定义为方法,则会执行三次:

(1 to 3) foreach {
  def line = Console.readLine
  i => println(line)
}

博客Scala for Java Refugees Part 6: Getting Over Java有一个关于高阶函数的有趣部分,包括:

  

Scala为这些高阶函数提供了更多的语法灵活性   在迭代调用中,我们创建一个完整的匿名方法,只是为了再次调用println(String)方法。
  考虑println(String)本身就是一个采用String并返回Unit的方法,人们会认为我们可以将其压缩一点。事实证明,我们可以:

iterate(a, println)
  

通过省略括号并仅指定方法名称,我们告诉Scala编译器我们要将println用作功能值,并将其传递给iterate方法。
  因此,我们不是仅仅为了处理一组调用而创建一个新方法,而是传递一个已经完成我们想要的旧方法。
  这是C和C ++中常见的模式。实际上,将函数作为函数值传递的语法完全相同。似乎有些事情永远不会改变......