假如我们定义如下的函数:

(x:Int) => x + more

这里我们引入一个自由变量more.它不是所定义函数的参数,而这个变量定义在函数外面,比如:

var more =1

那么我们有如下的结果:

scala> var more =1
more: Int = 1 scala> val addMore = (x:Int) => x + more
addMore: Int => Int = <function1> scala> addMore (100)
res1: Int = 101

这样定义的函数变量addMore 成为一个“闭包”,因为它引用到函数外面定义的变量,定义这个函数的过程是将这个自由变量捕获而构成一个封闭的函数。有意思的是,当这个自由变量发生变化时,Scala的闭包能够捕获到这个变化,因此Scala的闭包捕获的是变量本身而不是当时变量的值。

比如:

scala> more =  9999
more: Int = 9999 scala> addMore ( 10)
res2: Int = 10009

同样的,如果变量在闭包在发生变化,也会反映到函数外面定义的闭包的值。比如:

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
res4: Int = -11

可以看到在闭包中修改sum的值,其结果还是传递到闭包的外面。

如果一个闭包所访问的变量有几个不同的版本,比如一个闭包使用了一个函数的局部变量(参数),然后这个函数调用很多次,那么所定义的闭包应该使用所引用的局部变量的哪个版本呢? 简单的说,该闭包定义所引用的变量为定义该闭包时变量的值,也就是定义闭包时相当于保存了当时程序状态的一个快照。比如我们定义下面一个函数闭包:

scala> def makeIncreaser(more:Int) = (x:Int) => x + more
makeIncreaser: (more: Int)Int => Int scala> val inc1=makeIncreaser(1)
inc1: Int => Int = <function1> scala> val inc9999=makeIncreaser(9999)
inc9999: Int => Int = <function1> scala> inc1(10)
res5: Int = 11 scala> inc9999(10)
res6: Int = 10009

当你调用makeIncreaser(1)时,你创建了一个闭包,该闭包定义时more的值为1, 而调用makeIncreaser(9999)所创建的闭包的more的值为9999。此后你也无法修改已经返回的闭包的more的值。因此inc1始终为加一,而inc9999始终为加9999.

Scala闭包的更多相关文章

  1. Scala 闭包

    Scala 闭包 闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量. 闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另外一个函数. 如下面这段匿名的函数: val multipl ...

  2. python 本地变量和全局变量 locals() globals() global nonlocal 闭包 以及和 scala 闭包的区别

    最近看 scala ,看到了它的作用域,特此回顾一下python的变量作用域问题. A = 10 B = 100 print A #10 print globals() #{'A': 10, 'B': ...

  3. scala 闭包的概念

    闭包本质上是一个函数和其引用的变量的统一定义,它的返回值依赖于这个函数外部的一个或者多个变量. var test = (i:Int) => i+sum 这里 i是一个形参, 随着函数的调用传入不 ...

  4. Spark记录-Scala函数与闭包

    函数声明 Scala函数声明具有以下形式 - def functionName ([list of parameters]) : [return type] Scala 如果不使用等号和方法体,则隐式 ...

  5. scala中的闭包

    scala闭包 代码示例: package test.close_pack import scala.collection.mutable.ArrayBuffer /** * AUTHOR Guozy ...

  6. Scala函数式编程进阶

    package com.dtspark.scala.basics /** * 函数式编程进阶: * 1,函数和变量一样作为Scala语言的一等公民,函数可以直接赋值给变量: * 2, 函数更长用的方式 ...

  7. Scala入门之函数进阶

    /** * 函数式编程进阶: * 1,函数和变量一样作为Scala语言的一等公民,函数可以直接赋值给变量: * 2, 函数更长用的方式是匿名函数,定义的时候只需要说明输入参数的类型和函数体即可,不需要 ...

  8. 大数据系列修炼-Scala课程06

    关于Scala中的正则表达式与模式匹配结合的正则表达式Reg 正则表达式的实现:正则表达式的定义与其它语言差不多,只需在表达式后加一个.r,并且可以遍历相应的表达式进行匹配 //定义的正则表达式 va ...

  9. 一文学会Scala

    整体介绍 Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性. 联邦理工学院洛桑(EPFL)的Martin Odersky于2001 ...

随机推荐

  1. MySQL sql_slave_skip_counter

    因为mysql的主从复制是逻辑复制,所以slave在apply relay log的过程中,经常会遇到错误,而参数sql_slave_skip_counter可以设置跳过多少个event,让slave ...

  2. 转自 Good morning 的几句精辟的话

    1.志愿者招募 根据流量平衡方程来构图非常方便,而且简单易懂,以后可能成为做网络流的神法之一 简单记一下流量平衡方程构图法的步骤: a.列出需求不等式 b.通过设置松弛变量,将不等式变成等式 c.两两 ...

  3. epub显示特殊字体

    You need to open the ePub in an archive program (they are just ZIP files) and add an XML file to the ...

  4. 期待已久的2012年度最佳jQuery插件揭晓

    近日,国外著名博客WDL发布了2012年度最佳 jQuery 插件.jQuery 自2006年发布以来,经过6年的迅速发展,目前已是最流行和使用最广泛的 JavaScript 框架,这主要归功于众多围 ...

  5. Android 应用启动渐变效果

    /** * 应用程序启动类:显示欢迎界面并跳转到主界面 * @author liux (http://my.oschina.net/liux) * @version 1.0 * @created 20 ...

  6. LVS与其他负载均衡软件的区别

    有人在邮件列表问haproxy的作者为何haproxy无论是tcp模式还是http模式,能支撑的并发量都不是太大. Willy回答了这个问题.   Exactly. The difference is ...

  7. EF RepositoryBase 参考示例【转】

    1.定义泛型类 namespace Crm.Data.Logic.Repository{    public abstract class AbstractRepository<TC, T> ...

  8. Android之parseSDKContent failed

    由于之前安装ADT之后就一直报parseSDKContent failed的错误,具体的信息为:java.lang.NullPointerException. 此问题的情况为在Eclipse下,And ...

  9. Java笔记(二十七)……IO流中 File文件对象与Properties类

    File类 用来将文件或目录封装成对象 方便对文件或目录信息进行处理 File对象可以作为参数传递给流进行操作 File类常用方法 创建 booleancreateNewFile():创建新文件,如果 ...

  10. 五指CMS开发日志(一)

    开发了这么长时间,基本功能已经具备了.分享一下后台的界面吧.