Chapter 08 《Functions and Closur
2018-06-13 本文已影响5人
liqing151
- 随着程序的变大,要使用更小的函数将它们进行切分。切分的方法有
- 方法(以某个对象的成员形式存在的函数);
- 嵌套函数;
- 函数字面量;
- 函数值等。
方法
- 该函数作为某个对象的成员出现。非常类似于面向对象语言中的做法
局部函数
- 可以在函数内部定义函数,只在这个函数内部使用的函数最好定义在这个函数内,通常称为助手函数。
一等函数
- 在
Scala
中不仅可以定义和调用函数,还可以使用匿名函数,也就是函数字面量,并作为一个值进行传递。函数字面量被编译成类,并在运行时实例化为函数值。函数字面量存在于源码,函数值存在于运行过程中。(x: Int) => x + 1
- 在
- 函数字面量的简单写法:可以在编译器能够实现类型推断的情况下省去入参的类型标注。
- 为了使得函数字面量进一步精简,可以使用下划线作为占位符。用来表示一个或者多个参数,每个参数只出现一次。当下划线的类型不能使编译器推断出来类型时,需要使用类型标注进行声明。
部分应用函数
- 部分应用的函数是一个表达式,在这个表达式中,并不给出函数需要的所有参数,而是给出部分或者是完全不给。
def sum(a: Int, b: Int, c: Int) = a + b + c val a = sum _
使用方法a(1,2,3)
,编译器从sum _
生成了类,又生成了实例赋值给a
。该类带有一个接收三个参数的apply
函数,因为sum _
缺失的参数为3
个。编译器将a(1,2,3)
编译成为对apply
函数的调用,a(1,2,3)=>a.apply(1,2,3)
。val b = sum(1, _: Int, 3)
生成了只传递一个参数的apply
函数。(这一章节有些概念不是很明白,比如list.foreach(println _)=>list.foreach(println)
)
闭包
- 运行时从函数字面量创建出来的函数对象成为闭包。没有自由变量的函数字面量,比如
(x: Int) => x + 1
,称为闭合语,这里的语指的是一段代码。(x: Int) => x + more
,不是闭合的,需要在运行的时候捕获到自由变量more
从而闭合该函数字面量。此时创建的闭包包括了函数对象以及more
变量的引用,而不是值。
def makeIncreaser(more: Int) = (x: Int) => x + more scala> val inc1 = makeIncreaser(1) inc1: Int => Int = <function1> scala> val inc9999 = makeIncreaser(9999) inc9999: Int => Int = <function1>
创建了两个闭包。当调用
scala> inc1(10) res20: Int = 11 scala> inc9999(10) res21: Int = 10009
虽然more
被传入的方法makeIncreaser
已经结束,但是编译器保证被捕获的参数依然在堆上存活着。
特殊的函数调用形式
支持重复参数,带名字的参数以及缺省参数。
- 重复参数。
允许标识出函数的最后一个参数可以被重复。注意是最后一个参数,在参数类型的结尾加上*
号即可。加上星号可以传递0
个,1
个或者多个。在内部是一个Array[String]
的类型。但是不能直接传入一个Array
数组。需要将数组处理成为一个变参的形式,例如:
- 重复参数。
scala> def echo(args: String*) = for (arg <- args) println(arg) scala> val arr = Array("What's", "up", "doc?") scala> echo(arr: _*) //将arr中的每个元素分别传递给echo,而不是将其当做一个整体传递。
- 带名字的参数。
在普通的函数调用中,实参和形参是按照顺序进行匹配的。可以直接使用带名字的参数指定需要传入的参数以及需要传入的值,可以交换形参的位置。最常见的场合适合缺省参数一起使用
- 带名字的参数。
- 缺省参数。
缺省参数可以不出现在函数调用中,对应的参数会被填充为缺省值。设定多个缺省值的情况下,可以通过指定名字来确定需要传入的参数。
- 缺省参数。
尾递归
- 是
Scala
编译器对递归的一个优化,如果一个函数最后一部的动作是调用自己,那么这个函数就可被称为尾递归。编译器能够将尾递归优化成为循环,而不是开辟新的递归栈。仅限于函数在函数体中在最后一步直接调用自己。