4. 操作也是对象(Operations Are Objects)
Scala是一种函数式编程语言,也就是说每一个函数都是一个值。Scala有很简洁的语法用于定义匿名和curry化函数(curried function,functional programming的概念之一,名字源于Haskell Curry,Haskell的发明者,一般都不翻译。本文后面并没有针对这个概念的解释和实现,有兴趣者请参阅相关参考资料——译注),以及嵌套函数等。
4.1. 方法是函数式值(Methods are Functional Values)
为了演示如何将函数作为一个值使用,我们定义一个exists函数,用于检测一个数组当中是否有符合条件的元素:
def exists[T](xs: Array[T], p: T => Boolean) = {
var i: Int = 0
while (i < xs.length && !p(xs(i))) i = i + 1
i < xs.length
}
方法参数[T]表示数组类型是任意的(类型参数在5.1节中详细介绍),参数p表示验证条件也是任意的,p的类型是函数类型(function type)T=>Boolean,表示所有定义域是T类型,值域是Boolean的函数。函数参数可以像普通函数一样执行,如上面的循环体中显示的p被调用那样。以函数作为参数或者返回值的函数,称为高阶函数。
定义了exists,我们可以通过双重否定来定义一个函数forall,表示数组的所有元素没有一个不符合条件的,该函数定义如下:
def forall[T](xs: Array[T], p: T => boolean) = {
def not_p(x: T) = !p(x)
!exists(xs, not_p)
}
函数forall内部定义了一个嵌套函数not_p,表示不满足条件p。嵌套函数可以访问所在环境的函数参数和本地变量,例如not_p访问了forall的参数p。
Scala还可以定义一个没有名字的函数,例如下面这个简版的forall函数:
def forall_short[T](xs: Array[T], p: T => boolean) =
!exists(xs, (x: T) => !p(x))
其中(x: T) => !p(x)定义了一个匿名函数(anonymous function),将类型为T的参数p映射为!p(x)。
有了exists和forall,我们可以定义一个函数hasZeroRow,用以检验一个二维矩阵是否有一行全是0:
def hasZeroRow(matrix: Array[Array[int]]) =
exists(matrix, (row: Array[int]) => forall(row, 0 ==))
表达式forall(row, 0 ==)用于检测row是否只包含0。这里,0的==方法被作为参数传递给forall的参数p,这显示了方法本身也是值,有点类似于C#中的“delegates”。