object ScalaApp extends App {
def detail(name: String, age: Int = 88): Unit = println(name + ":" + age)
// 如果没有传递 age 值,则使用默认值
detail("heibaiying")
detail("heibaiying", 12)
}
2. 闭包
2.1 闭包的定义
var more = 10
// addMore 一个闭包函数:因为其捕获了自由变量 more 从而闭合了该函数字面量
val addMore = (x: Int) => x + more
如上函数 addMore 中有两个变量 x 和 more:
x : 是一个绑定变量 (bound variable),因为其是该函数的入参,在函数的上下文中有明确的定义;
more : 是一个自由变量 (free variable),因为函数字面量本生并没有给 more 赋予任何含义。
按照定义:在创建函数时,如果需要捕获自由变量,那么包含指向被捕获变量的引用的函数就被称为闭包函数。
2.2 修改自由变量
这里需要注意的是,闭包捕获的是变量本身,即是对变量本身的引用,这意味着:
闭包外部对自由变量的修改,在闭包内部是可见的;
闭包内部对自由变量的修改,在闭包外部也是可见的。
// 声明 more 变量
scala> var more = 10
more: Int = 10
// more 变量必须已经被声明,否则下面的语句会报错
scala> val addMore = (x: Int) => {x + more}
addMore: Int => Int = $$Lambda$1076/1844473121@876c4f0
scala> addMore(10)
res7: Int = 20
// 注意这里是给 more 变量赋值,而不是重新声明 more 变量
scala> more=1000
more: Int = 1000
scala> addMore(10)
res8: Int = 1010
2.3 自由变量多副本
自由变量可能随着程序的改变而改变,从而产生多个副本,但是闭包永远指向创建时候有效的那个变量副本。
// 第一次声明 more 变量
scala> var more = 10
more: Int = 10
// 创建闭包函数
scala> val addMore10 = (x: Int) => {x + more}
addMore10: Int => Int = $$Lambda$1077/1144251618@1bdaa13c
// 调用闭包函数
scala> addMore10(9)
res9: Int = 19
// 重新声明 more 变量
scala> var more = 100
more: Int = 100
// 创建新的闭包函数
scala> val addMore100 = (x: Int) => {x + more}
addMore100: Int => Int = $$Lambda$1078/626955849@4d0be2ac
// 引用的是重新声明 more 变量
scala> addMore100(9)
res10: Int = 109
// 引用的还是第一次声明的 more 变量
scala> addMore10(9)
res11: Int = 19
// 对于全局而言 more 还是 100
scala> more
res12: Int = 100
从上面的示例可以看出重新声明 more 后,全局的 more 的值是 100,但是对于闭包函数 addMore10 还是引用的是值为 10 的 more,这是由虚拟机来实现的,虚拟机会保证 more 变量在重新声明后,原来的被捕获的变量副本继续在堆上保持存活。