到本章这里,所有函数文本的例子仅参考了传入的参数。例如,(x: Int) => x > 0里,函数体用到的唯一变量,x > 0,是x,被定义为函数参数。然而也可以参考定义在其它地方的变量:
(x: Int) => x + more // more是多少?
函数把“more”加入参考,但什么是more呢?从这个函数的视点来看,more是个自由变量:free variable,因为函数文本自身没有给出其含义。相对的,x变量是一个绑定变量:bound variable,因为它在函数的上下文中有明确意义:被定义为函数的唯一参数,一个Int。如果你尝试独立使用这个函数文本,范围内没有任何more的定义,编译器会报错说:
scala> (x: Int) => x + more < console>:5: error: not found: value more (x: Int) => x + more ˆ
另一方面,只要有一个叫做more的什么东西同样的函数文本将工作正常:
scala> var more = 1 more: Int = 1 scala> val addMore = (x: Int) => x + more addMore: (Int) => Int = < function> scala> addMore(10) res19: Int = 11
依照这个函数文本在运行时创建的函数值(对象)被称为闭包:closure。名称源自于通过“捕获”自由变量的绑定对函数文本执行的“关闭”行动。不带自由变量的函数文本,如(x: Int) => x + 1,被称为封闭术语:closed term,这里术语:term指的是一小部分源代码。因此依照这个函数文本在运行时创建的函数值严格意义上来讲就不是闭包,因为(x: Int) => x + 1在编写的时候就已经封闭了。但任何带有自由变量的函数文本,如(x: Int) => x + more,都是开放术语:open term。因此,任何依照(x: Int) => x + more在运行期创建的函数值将必须捕获它的自由变量,more,的绑定。由于函数值是关闭这个开放术语(x: Int) => x + more的行动的最终产物,得到的函数值将包含一个指向捕获的more变量的参考,因此被称为闭包。
这个例子带来一个问题:如果more在闭包创建之后被改变了会发生什么事?Scala里,答案是闭包看到了这个变化。如下:
scala> more = 9999 more: Int = 9999 scala> addMore(10) res21: Int = 10009
直觉上,Scala的闭包捕获了变量本身,而不是变量指向的值。相对的,Java的内部类根本不允许你访问外围范围内可以改变的变量,因此到底是捕获了变量还是捕获了它当前具有的值就没有差别了。就像前面演示的例子,依照(x: Int) => x + more创建的闭包看到了闭包之外做出的对more的变化。反过来也同样。闭包对捕获变量作出的改变在闭包之外也可见。下面是一个例子:
scala> val someNumbers = List(-11, -10, -5, 0, 5, 10) someNumbers: List[Int] = List(-11, -10, -5, 0, 5, 10) scala> var sum = 0 sum: Int = 0 scala> someNumbers.foreach(sum += _) scala> sum res23: Int = -11
以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索int
, 函数
, 变量
, 闭包
, scala
, 文本
, more
文本函数
,以便于您获取更多的相关知识。