函数和闭包
当程序变得庞大时,你需要一些方法把它们分割成更小的,更易管理的片段。为了分割控制流,Scala 提供了所有有经验的程序员都熟悉的方式:把代码分割成函数。
实际上,Scala 提供了许多Java 中没有的定义函数的方式。除了作为对象成员函数的方法之外,还有内嵌在函数中的函数,函数文本和函数值。本章带你体会所有 Scala 中的这些函数的风味。
1.方法
带私有的 processLine 方法的 LongLines 对象
import scala.io.Source
object LongLines {
def processFile(filename: String, width: Int) {
val source = Source.fromFile(filename)
for (line <- source.getLines)
processLine(filename, width, line)
}
private def processLine(filename:String, width:Int, line:String) {
if (line.length > width)
println(filename+": "+line.trim)
}
}
2.本地函数
上节中 processFile 方法的建立演示了函数式编程风格的一个重要设计原则:程序应该被解构成若干小的函数,每个完成一个定义良好的任务。
Java 里,达成这个目的的主要工具是 private 方法。这种私有方法的方式在 Scala 里同样有效,如代码 8.1 里描述的,但是 Scala 提供了另一种方式:你可以把函数定义在另一个函数中。就好象本地变量那样,这种本地函数仅在包含它的代码块中可见。以下是一个例子:
def processFile(filename: String, width: Int) {
def processLine(filename:String, width:Int, line:String) {
if (line.length > width)
print(filename+": "+line)
}
val source = Source.fromFile(filename)
for (line <- source.getLines) {
processLine(filename, width, line)
}
}
在这个例子中,我们通过把私有方法,processLine,转换为本地方法,processFile ,既然 processLine 被定义在 processFile 里,另一个改善变为可能了。请注意 filename 和 width是怎样不改变地传入到帮助函数中。这不是必须的,因为本地函数可以访问包含它们的函数的参数。你可以直接使用外部 processLine 函数的参数 。
3.函数式第一类值
Scala 拥有第一类函数:first-class function。你不仅可以定义函数和调用它们,还可以把函数写成没有名字的文本:literal 并把它们像值:value 那样传递。函数文本被编译进一个类,类在运行期实例化的时候是一个函数值:function value。
以下是对数执行递增操作的函数文本的简单例子:
(x: Int) => x + 1
=>指明这个函数把左边的东西(任何整数x)转变成右边的东西(x + 1)。所以,这是一个把任何整数x映射为x + 1的函数。
函数值是对象,所以如果你愿意可以把它们存入变量。它们也是函数,所以你可以使用通常的括号函数调用写法调用它们。以下是这两种动作的例子:
scala> var increase = (x: Int) => x + 1
increase: (Int) => Int = <function>
scala> increase(10)
res0: Int = 11
本例中,因为 increase 是 var,你可以在之后重新赋给它不同的函数值。
scala> increase = (x: Int) => x + 9999
集合类型还有 filter 方法
scala> someNumbers.filter((x: Int) => x > 0)
res6: List[Int] = List(5, 10)
4.函数文本短格式
scala> someNumbers.filter((x) => x > 0)
res7: List[Int] = List(5, 10)
5.占位符语法
如果想让函数文本更简洁,可以把下划线当做一个或更多参数的占位符,只要每个参数在函数文
本内仅出现一次。比如,_ > 0对于检查值是否大于零的函数来说就是非常短的标注:
scala> someNumbers.filter(_ > 0)
res9: List[Int] = List(5, 10)
scala> def sum(a: Int, b: Int, c: Int) = a + b + c
sum: (Int,Int,Int)Int
scala> val f = (_: Int) + (_: Int)
f: (Int, Int) => Int = <function>
scala> f(5, 10)
res11: Int = 15