学习Scala的闭包

到本章这里,所有函数文本的例子仅参考了传入的参数。例如,(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
文本函数
,以便于您获取更多的相关知识。

时间: 2024-08-01 12:14:32

学习Scala的闭包的相关文章

怎样学习Scala泛函编程

     确切来说应该是我打算怎么去学习Scala泛函编程.在网上找不到系统化完整的Scala泛函编程学习资料,只好把能找到的一些书籍.博客.演讲稿.论坛问答.技术说明等组织一下,希望能达到学习目的.关于Scala语言的教材在国内网上还是比较容易找到的:可以到Scala语言官方网站,国内Scala社区网站这些地方去看看了解一下:深一点的参考一下在路上,里面包括了一些泛函编程的概念性内容.     学习编程语言除了语法语意之外还必须透彻了解编程语言的数据结构(data structure):数据结

学习javascript的闭包,原型,和匿名函数之旅_javascript技巧

本文通过示例给大家介绍javascript的闭包,原型,和匿名函数,具体详情请看下文. 一 .>关于闭包 理解闭包 需要的知识 1.变量的作用域 例1: var n =99; //建立函数外的全局变量 function readA(){ alert(n); //读取全局变量 } readA(); //执行此函数 例2: function readB(){ var c = 9; function readC(){ console.log(c); //ok c可见 } return readC; }

学习Scala第一篇-从hello World开始

最近开始系统性的学习scala.其实之前使用过scala的,比如我在用Gatling这款性能测试工具的时候就接触到了scala了.Gatling本身就是用Scala写的,而且Gatling的性能测试配置文件本身就是一个scala类,可以随意使用scala甚至是Java提供的各种类库.当时觉得用Gatling特别舒服的原因就在于配置文件强大的表现力.而这种表现力就是由Scala语言提供的. 言归正传,学习Scala还是从最简单的Hello world开始.在Scala官网中显著的标题就是: Obj

想涨工资吗?那就学习Scala,Golang或Python吧

[编者按]据薪水调查机构 PayScale 提供的数据显示,掌握 Scala,Golang 和 Python 语言以及诸如 Apache Spark 之类的大数据技术,能带来最大的薪水提升.本文作者为 Serdar Yegulalp,文章系国内 ITOM 管理平台 OneAPM 编译呈现. 想涨工资?先学一门新技能. 从哪一门开始学习呢?根据 PayScale(IT及其他行业薪水调查机构)提供的数据显示,Go,Scala和诸如Apache Spark和Hadoop等大数据技术都是不错的选择.Pa

跟我学习javascript的闭包_javascript技巧

JavaScript 闭包究竟是什么? 用JavaScript一年多了,闭包总是让人二丈和尚摸不着头脑.陆陆续续接触了一些闭包的知识,也犯过几次因为不理解闭包导致的错误,一年多了资料也看了一些,但还是不是非常明白,最近偶然看了一下 jQuery基础教程 的附录,发现附录A对JavaScript的闭包的介绍简单易懂,于是借花献佛总结一下. 1.定义 闭包:是指有权访问另外一个函数作用域中的变量的函数.创建闭包的常见方式就是在一个函数内部创建另外一个函数. 直接上例子 function a(){ v

ruby学习笔记(7)-闭包

闭包的一个重要特征是:过程(方法)内部定义的变量,即使在方法调用完成以后,仍然可以继续引用到!(即延长了生命周期) def method(n) puts "n=#{n}"; #测试用 return proc{|i| n +=i } #关键:proc是一个过程对象,只能由"委托"用call来调用,这里在过程内部引用了参数变量n,将会在多次call该过程后,保留对n的引用,形成闭包! end aDelegate = method(0);#可以理解为c#中的委托,同时该语

JavaScript学习总结(三)——闭包、IIFE、原型、函数与对象

一.闭包(Closure) 1.1.闭包相关的问题 请在页面中放10个div,每个div中放入字母a-j,当点击每一个div时显示索引号,如第1个div显示0,第10个显示9:方法:找到所有的div,for循环绑定事件. 示例代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>闭包</title> <style type="

学习Scala的二维布局库和抽象类

二维布局库 作为本章运行的例子,我们将创造一个制造和渲染二维布局元素的库.每个元素 将代表一个填充字符的长方形.方便起见,库将提供名为"elem"的工厂方法来通过传入的 数据构造新的元素.例如,你将能通过工厂方法采用下面的写法创建带有字串的元素: elem (s: String): Element 正如你所见,元素将以名为Element的类型为模型.你将能在元素上 调用above或beside,传入第二个元素,从而得到合并了这两个的新元素.例如,下面的表达式将构建一 个包含两列,每列高

学习Scala的定义工厂对象

你现在有了布局元素的类层级.这个层级可以"依原件"展现给你的客户.但是你或许还是选择把层 级隐藏在工厂对象之后.工厂对象包含了构建其它对象的方法.客户与实惠使用这些工厂方法实现对象 的构造而不是直接使用new构造对象.这种方式的一个好处是对象的创建可以被集中化并且对象实际代表 类的细节可以被隐藏.这种隐藏一方面简化客户理解你的库,因为更少的细节被暴露出来,另一方面提 供给你更多机会在之后改变库的实现而不会破坏客户代码. 为布局元素构建工厂的第一任务是选择工厂方法应该放在哪儿.它们应该是