scala中闭包的使用

The*_*rii 2 scala

我是斯卡拉新手。我在阅读有关闭包的内容时发现了闭包的定义:

“该名称源自通过“捕获”其自由变量的绑定来“关闭”函数文字的行为”。

这行代码实际上意味着什么?关闭到底有何帮助?它的用例是什么?

And*_*kin 7

什么是自由变量?

考虑柯里化乘法的函数文字:

(x: Int) => (y: Int) => x * y
Run Code Online (Sandbox Code Playgroud)

如果仅考虑子表达式e := ,则可以按如下方式递归计算e中的自由变量(y: Int) => x * y集(从叶子和开始,然后从其部分构建表达式):xy

  • FREE(x) = {x}因为x是一个变量
  • FREE(y) = {y}因为y是一个变量
  • FREE(*) = {}因为*是一个内置常数,用于所有实际目的
  • FREE(x * y) = FREE(*) U FREE(x) U FREE(y) = {} U {x} U {y} = {x, y}通过递归下降到子树
  • FREE( (y: Int) => x * y ) = FREE(x * y) - {y} = {x, y} - {y} = {x},因为该变量y受内联函数定义的约束,因此变量yfromFREE(x * y)不再是自由的。

因此变量在表达式中y绑定的并且x自由的(y: Int) => x * y


什么是闭包?

现在,如果您采用整个表达式(x: Int) => (y: Int) => x * y并将其应用于某个常数(7例如 ),会发生什么?返回什么?

返回的对象是表达式的闭包(y: Int) => x * y,其中自由变量x设置为 value 7。所以,从某种意义上来说,结果是

((x: Int) => (y: Int) => x * y)(7)
Run Code Online (Sandbox Code Playgroud)

类似于具有单一方法的对象,看起来大致像

class y_to_x_times_y_closure(x: Int) {
  def apply(y: Int) = x * y
}
Run Code Online (Sandbox Code Playgroud)

实例化为y_to_x_times_y_closure(7). 请注意,该值7不能驻留在某些函数的调用堆栈中,因为您可以轻松地生成一大堆闭包,例如

for (i <- 0 to 1000) yield ((x: Int) => (y: Int) => x * y)(i))
Run Code Online (Sandbox Code Playgroud)

必须在同一个线程中同时共存,并且不同的捕获值i绑定到变量x。因此,Scala 中的闭包被实现为堆驻留对象。


为什么这有用?

这实际上是一个太宽泛的问题:它使您能够进行函数式编程。它深深地内置于语言中,如果不到处使用大量的闭包,你就无法真正做任何事情。

考虑以下简单示例:打印一位数字的乘法表:

for (x <- 1 to 9) {
  for (y <- 1 to 9) {
    printf("%3d", x * y)
  }
  println()
}
Run Code Online (Sandbox Code Playgroud)

这会产生:

  1  2  3  4  5  6  7  8  9
  2  4  6  8 10 12 14 16 18
  3  6  9 12 15 18 21 24 27
  4  8 12 16 20 24 28 32 36
  5 10 15 20 25 30 35 40 45
  6 12 18 24 30 36 42 48 54
  7 14 21 28 35 42 49 56 63
  8 16 24 32 40 48 56 64 72
  9 18 27 36 45 54 63 72 81
Run Code Online (Sandbox Code Playgroud)

这些循环实际上被脱糖到对象for上的以下方法应用程序中:Range1 to 9

 (1 to 9) foreach { x => 
   (1 to 9) foreach { y =>
     printf("%3d", x * y)
   }
   println()
 }
Run Code Online (Sandbox Code Playgroud)

y => printf("%3d", x * y)传递给内部的 -thing是什么 foreach?它实际上是一个带有自由变量的表达式x。为了打印任何有意义的内容,它必须捕获 的值x,该值又由外部设置1为值。因此,内部与的闭包一起工作,其中被设置为值to 。9foreachforeachy => printf("%3d", x * y)x19