函数是“头等公民”,可以像任何其他数据类型一样被传递和操作。
val num=3.14
val fun=ceil_//这里将max方法转成了函数并作为值赋予给了fun变量。
//fun的类型是(Double)=>Double
fun(num)//4.0,调用fun
Array(3.14,1.42,2.0).map(fun)
//Array(4.0,2.0,2.0),将fun传递给Array中的每一个元素
def valueAtOneQuarter ( f:(Double)=>Double ) = f(0.25)
valueAtOneQuarter(ceil_) //1.0 , ceil(0.25)
valueAtOneQuarter(sqrt_) //0.5 , sqrt(0.25)
//这里函数valueAtOneQuarter的参数是 函数f:(Double)=>Double
//valueAtOneQuarter的类型是: ( (Double)=>Double )=>Double
一个例子:
def mulBy(factor:Double) = (x:Double)=>factor * x
//mulBy的类型为 Double => ( (Double)=>Double )
//mulBy接受一个Double参数,产出一个 (Double)=>Double 的函数
val quintuple = mulBy(5) // (x:Double)=> 5 * x
quintuple(20) //100
map:将一个函数应用到某个集合的所有元素并返回值。
(1 to 9).map(0.1 * _) // (0.1,0.2,0.3,...,0.9)
foreach:将一个函数应用到某个集合所有元素但不返回值。
(1 to 9).map("*" * _).foreach(println _) // 打印出一个直角三角形
fliter:输出所有匹配某个特定条件的元素。
(1 to 9).filter(_ %2== 0) // 2,4,6,8
reduceLeft: 接受一个二元函数,并将它应用到序列中的所有元素,从左到右
(1 to 9).reduceLeft(_ * _) //(...((1*2)*3)*4....*9)
sortWith: 二元函数,排序。
"Mary has a little lamb.".split(" ").sortWith(_.length<_.length)
//输出一个按长度递增排序的数组。
柯里化的表现形式是:一个带有分开的两个参数(两个括号)的函数。
将原来接受两个参数的函数变成新的接受一个参数的过程,新的函数返回一个以原有第二个参数作为参数的函数。
def mul(x:Int,y:Int)=x*y
def mulOneAtTime(x:Int)=(y:Int)=>x*y
def mulOneAtTime(x:Int)(y:Int)=x*y //上一步的简写
mul(6,7) //42
mulOneAtTime(6)(7) //42
将一系列与归组成不带参数也没有返回值的函数。
def until(condition:=>Boolean) (block:=>Unit) {
//这里将 condition:()=>Boolean 省略成了 condition:=>Boolean
//这个参数叫“换名调用参数”,与“换值调用参数不同”,函数调用时,参数表达式不会被求值。表达式成为无参函数的函数体,而该函数被当作参数传递下去
if (! condition) {
block
until(condition) (block)
}
}
var x=10
until(x==0){
x-=1
println(x)
}
在上例中,until是柯里化过的。先处理condition,然后把block当作完全独立的另一个参数。如果没有柯里化,我们在调用until时:
until(x==0,{...}) //就没那么漂亮了
函数的返回值就是函数体的值(最后一个式子),不需要用return来返回函数值。
但,return从一个匿名函数中返回一个值给包含这个匿名函数的带名函数,这对于控制抽象是很有用的。
def indexOf(str:String,ch:Char):Int={
var i= 0
until (i==str.length){
if(str(i)==ch) return i
i+=1
}//这个匿名函数的值传递给until。
return -1 //当这句话执行时,indexOf终止并返回-1。我们需要在带名函数定义时给出返回值类型 " Int= "
}
高阶函数即是函数的迭代功能,函数的参数可以是另一个函数,我们在使用高阶函数时应分析其参数类型及产出结果类型。
柯里化是一个有用的手段,它表示了一个处理过程的分段化,其实可以看成高阶函数的另一面。
控制抽象,名字来源应该是他代表控制结构的抽象化,我们可以使用换命调用方法简化控制结构的代码。知道原理即可。