scala学习手记30 - 闭包
首先要弄白闭包的概念。
教材中的说法是:闭包是一种特殊的函数值,闭包中封闭或绑定了在另一个作用域或上下文中定义的变量。这里说闭包是一种特殊的函数值。
维基百科中的说法是:在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。运行时,一旦外部的函数被执行,一个闭包就形成了,闭包中包含了内部函数的代码,以及所需外部函数中的变量的引用。其中所引用的变量称作上值(upvalue)。这里说,闭包是引用了自由变量的函数,是函数。
到目前为止的scala程序例子里,用于函数值或代码块的变量和值都是绑定的。我们清楚的知道它们都绑定到哪儿,可以是局部变量或是参数。此外,还可以创建有未绑定变量的代码块。调用函数之前,必须绑定它们;不过,它们可以在局部范围和参数列表之外绑定变量。这就是称它们为闭包的原因。
开始正式的程序说明。
先来看这一段代码:
def loopThrough(number: Int)(closure: Int => Unit) {
for (i <- 1 to number) {
closure(i)
}
}
var result = 0
val addIt = { value: Int => result += value }
loopThrough(10) { addIt }
println("Total of values from 1 to 10 is " + result)
result = 0
loopThrough(5) { addIt }
println("Total of values from 1 to 5 is " + result)
上面的代码先创建了一个函数loopTotal()。在这个函数中,从1到第一个参数number之间的值都会参与到第二个参数函数值closure的运算中。
比较特殊的是addIt代表的函数值,在函数值addIt的代码块中,变量value被绑定到参数中,但是代码块中的result却不是在块中或参数列表中定义的。addIt中的result实际上是绑定在外部的变量result上。
随后的代码演示了如何使用闭包。在loopThrough中的每一次运算都会修改result的值。
需要注意的是,闭包中的绑定并不是获得闭包绑定变量值的一份副本,而是直接绑定到变量本身。因此如果将result的值重置为0,闭包也会看到这种变化。下面是另一个例子,闭包绑定到另一个变量product上:
var product = 1
loopThrough(6){product *= _}
println("Product of values from 1 to 5 is " + product)
在上面的代码里,_指向loopThrough()所传入的参数,product绑定到loopThrough()的调用方里叫这个名字的变量上。
看看三次调用loopThrough函数的结果:

这一节勉强算是学完了,但是对于闭包这个概念还是不甚了了。不清楚的地方有这么几点:
- 闭包是什么,是方法?是函数?还是函数值?普通方法是不是也可以视为函数?
- 闭包中是会有一个自由变量的,这个自由变量具体是可以在哪里定义?是在函数里定义?还是在类里定义的?
- 如果闭包就是普通的方法或函数,变量也可以在类里定义,那java中的getter方法是不是也可以被叫做闭包?!显然是不可以的,但是为什么?
- 目前比较可以确定的一点就是在scala中函数值如果引用了外部变量,那么函数值是可以被称为闭包的。但是闭包是不是就一定是函数值?
- 在scala之外的其他语言,闭包是不是也可以当做函数值来使用?
#########
scala学习手记30 - 闭包的更多相关文章
- scala学习手记38 - 方法命名约定和for表达式
方法命名约定 之前在学习<运算符重载>一节时曾经说过一个方法命名约定:方法的第一个字符决定了方法的优先级.现在再说另一个命名约定:如果方法以冒号(:)结尾,则调用目标是运算符后面的实例. ...
- scala学习手记23 - 函数值
scala的一个最主要的特性就是支持函数编程.函数是函数编程中的一等公民:函数可以作为参数传递给其他函数,可以作为其他函数的返回值,甚至可以在其它函数中嵌套.这些高阶函数称为函数值. 举一个简单的例子 ...
- scala学习手记17 - 容器和类型推断
关于scala的类型推断前面已经提到过多次.再来看一下下面这个例子: import java.util._ var list1: List[Int] = new ArrayList[Int] var ...
- scala学习手记8 - 自适应的默认做法
scala有一些默认做法,会让代码更简洁.更易读写,下面列出了这样几个特性: 1. 支持脚本.scala支持脚本,因此无须将所有的代码都放到类里.如果脚本可以满足需求,就将代码放到一个脚本里,无须再创 ...
- Scala学习手记1 - 快速体验
又重新开始了scala的学习,因为中断了太长时间,所以这次还得从零开始.学习的过程就记录在这个博客上了. 这次学习的教程是<scala程序设计 java虚拟机多核编程实战>,我在多看上买了 ...
- scala 学习笔记三 闭包
闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量. 闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另外一个函数. 如下面这段匿名的函数: val multiplier = (i: ...
- scala学习手记40 - 使用case类
前面两节我们已经多次接触过case关键字了.case关键字不仅可以用在match/case中来执行模式匹配,也可以用来修饰类.不过用case修饰的类也主要是用来做模式匹配.在上一节曾经提到过match ...
- scala学习手记40 - case表达式里的模式变量和常量
再来看一下之前的一段代码: def process(input: Any) { input match { case (a: Int, b: Int) => println("Proc ...
- scala学习手记39 - 模式匹配
在java中有switch/case这样的模式匹配语句,可以匹配的类型包括int,byte,char,short, enum,在java8又支持了字符串. 在scala中也有类似的模式匹配语句,即ma ...
随机推荐
- Less-css基础扩展
//扩展Extend less的伪类,合并了选择器,放在与它引用匹配的选择器上 Use Method:以在study上扩展test的样式为例 .test{ color:#000000; font-si ...
- delphi ---break,exit,continue等跳出操作的区别
1.break 强制退出最近的一层循环(注意:只能放在循环里:而且是只能跳出最近的一层循环),用于从for.while.repeat语句中强制退出 2.continue 用于从for.while.re ...
- php 图片验证码
1.原理 数组中每个图片对应一个值->随机值->获取并保存到$_SESSION中,->获取随机值对应的图片,->通过__FILE__输出图片,->浏览器验证 2.代码 c ...
- https://help.aliyun.com/knowledge_detail/49787.html?spm=a2c4g.11186631.2.3.6f856f39tiE98P
https://help.aliyun.com/knowledge_detail/49787.html?spm=a2c4g.11186631.2.3.6f856f39tiE98P
- Vue1.0常用语法
摘要: var vm = new Vue({ el: "选择器", 挂载到页面的那个元素里,即确定vue的作用范围 外部可通过vm.$el访问,得到的是一个原生dom元素,可进行对 ...
- Linux基础命令(二)
作业一:1) 新建用户natasha,uid为1000,gid为555,备注信息为“master” groupadd -g 555 netasha useradd -u 1000 -g netasha ...
- git "Could not read from remote repository.Please make&n
git "Could not read from remote repository.Please make sure you have the correct access rights. ...
- (数据库之pymysql)
权限管理http://www.cnblogs.com/linhaifeng/articles/7267587.html#_label6一.pymysql模块(安装与查询) 1.安装pymysql(py ...
- Java中Collections和Collection的区别
java.util.Collection Collection 层次结构 中的根接口.Collection 表示一组对象,这些对象也称为 collection 的元素.一些 collection 允许 ...
- Go 结构体和map等数据结构转json字符串
Go语言中使用json包中的 Marshal() 函数将数据结构转成json字符串,源代码: func Marshal(v interface{}) ([]byte, error) { e := ne ...