函数和闭包
一、函数
1.1 函数与方法
Scala 中函数与方法的区别非常小,如果函数作为某个对象的成员,这样的函数被称为方法,否则就是一个正常的函数。
1 | // 定义方法 |
也可以使用 def
定义函数:
1 | def multi3 = (x: Int) => {x * x} |
multi2
和 multi3
本质上没有区别,这是因为函数是一等公民,val multi2 = (x: Int) => {x * x}
这个语句相当于是使用 def
预先定义了函数,之后赋值给变量 multi2
。
1.2 函数类型
上面我们说过 multi2
和 multi3
本质上是一样的,那么作为函数它们是什么类型的?两者的类型实际上都是 Int => Int
,前面一个 Int 代表输入参数类型,后面一个 Int 代表返回值类型。
1 | scala> val multi2 = (x: Int) => {x * x} |
1.3 一等公民&匿名函数
在 Scala 中函数是一等公民,这意味着不仅可以定义函数并调用它们,还可以将它们作为值进行传递:
1 | import scala.math.ceil |
在 Scala 中你不必给每一个函数都命名,如 (x: Int) => 3 * x
就是一个匿名函数:
1 | object ScalaApp extends App { |
1.4 特殊的函数表达式
1. 可变长度参数列表
在 Java 中如果你想要传递可变长度的参数,需要使用 String ...args
这种形式,Scala 中等效的表达为 args: String*
。
1 | object ScalaApp extends App { |
2. 传递具名参数
向函数传递参数时候可以指定具体的参数名。
1 | object ScalaApp extends App { |
3. 默认值参数
在定义函数时,可以为参数指定默认值。
1 | object ScalaApp extends App { |
二、闭包
2.1 闭包的定义
1 | var more = 10 |
如上函数 addMore
中有两个变量 x 和 more:
- x : 是一个绑定变量 (bound variable),因为其是该函数的入参,在函数的上下文中有明确的定义;
- more : 是一个自由变量 (free variable),因为函数字面量本生并没有给 more 赋予任何含义。
按照定义:在创建函数时,如果需要捕获自由变量,那么包含指向被捕获变量的引用的函数就被称为闭包函数。
2.2 修改自由变量
这里需要注意的是,闭包捕获的是变量本身,即是对变量本身的引用,这意味着:
- 闭包外部对自由变量的修改,在闭包内部是可见的;
- 闭包内部对自由变量的修改,在闭包外部也是可见的。
1 | // 声明 more 变量 |
2.3 自由变量多副本
自由变量可能随着程序的改变而改变,从而产生多个副本,但是闭包永远指向创建时候有效的那个变量副本。
1 | // 第一次声明 more 变量 |
从上面的示例可以看出重新声明 more
后,全局的 more
的值是 100,但是对于闭包函数 addMore10
还是引用的是值为 10 的 more
,这是由虚拟机来实现的,虚拟机会保证 more
变量在重新声明后,原来的被捕获的变量副本继续在堆上保持存活。
三、高阶函数
3.1 使用函数作为参数
定义函数时候支持传入函数作为参数,此时新定义的函数被称为高阶函数。
1 | object ScalaApp extends App { |
3.2 函数柯里化
我们上面定义的函数都只支持一个参数列表,而柯里化函数则支持多个参数列表。柯里化指的是将原来接受两个参数的函数变成接受一个参数的函数的过程。新的函数以原有第二个参数作为参数。
1 | object ScalaApp extends App { |
这里当你调用 curriedSum 时候,实际上是连着做了两次传统的函数调用,实际执行的柯里化过程如下:
- 第一次调用接收一个名为
x
的 Int 型参数,返回一个用于第二次调用的函数,假设x
为 2,则返回函数2+y
; - 返回的函数接收参数
y
,并计算并返回值2+3
的值。
想要获得柯里化的中间返回的函数其实也比较简单:
1 | object ScalaApp extends App { |
柯里化支持多个参数列表,多个参数按照从左到右的顺序依次执行柯里化操作:
1 | object ScalaApp extends App { |
参考资料
- Martin Odersky . Scala 编程 (第 3 版)[M] . 电子工业出版社 . 2018-1-1
- 凯.S.霍斯特曼 . 快学 Scala(第 2 版)[M] . 电子工业出版社 . 2017-7