概述
高阶函数是指使用其他函数作为参数、或者返回一个函数作为结果的函数。在Scala中函数是“一等公民”,所以允许定义高阶函数。这里的术语可能有点让人困惑,我们约定,使用函数值作为参数,或者返回值为函数值的“函数”和“方法”,均称之为“高阶函数”。
1.作为值的函数
在scala中,函数就像其他数据一样,你可以在变量中存放函数:
def main(args: Array[String]): Unit = {
val n = fun _ // _表示将函数fun作为一个值赋给了变量n,相当于该函数又有了一个名字n
val result = n(3)
println(result) //2
}
def fun(x:Int): Int ={
x-1
}
2.匿名函数
scala中,不需要给每个函数命名,正如你不需要给每个数字命名一样。以下是一个匿名函数:
(x:Int)=>x-1
相当于把一个函数简写了:
def fun(x:Int): Int ={
x-1
}
同样,匿名函数也可以赋给一个变量:
val f = (x:Double)=>x-1
Array(3.12,5.23,8.35).map(f).foreach(println)
//这里map中得函数变量将集合里的每个元素-1
Array(3.12,5.23,8.35) map{f} foreach(println)
//也可以使用{}以及中置表示法(没有句点),这种方法比较常见
3.函数参数
(1)基本用法:
函数既然可以被当作变量以及使用匿名函数简写,当然也能被当作参数,这便是高阶函数最终形奥义。
在一般函数中,使用的都是基本数据类型作为参数:
def fun(a:Int,b:Double):Double={
a+b
}
把简写的函数当作参数和基本参数放进一个函数(高阶)里,解决更复杂的逻辑:
def fun(x: Int, f: (Double) => Double): Double = f(x)
一般格式:
def 函数名 (…,函参名(参数类型)=>结果类型)=表达式/调用函数参数
(2)产生新的函数
def main(args: Array[String]): Unit = {
val newfun = mulFun(5) //这里返回了一个5*x的函数
print(newfun(3)) //15
}
def mulFun(factoy:Int)=(x:Int)=>x*factoy //返回一个匿名函数
疑问:这和在普通函数里调用其他函数有什么不一样吗?
- 如果将一个数值9和一个函数Math.sqrt传入上述高阶函数中:
val res = fun(9, Math.sqrt) //3.0
- 或者将9和自定义的平方函数传入:
val res = fun(9,(x:Double)=>x*x) //81.0
结论:普通方法只能一次性的调用一种功能,高阶函数通过传入不同的函数参数可以自由选择,完成更多种功能,更灵活多变一些。
(3)自动推断
当你将一个匿名函数当作参数传给另一个函数时,scala会自动帮你推断函数的类型信息:
比如,你的代码原本是这样的:
val res = fun(9,(x:Double)=>x*2)
可以写成这样:
val res = fun(9,_*2)
注意:只有当参数只在后面出现一次,才能用_替代
从舒适度上来讲,这是终极版本了,但前提是这些简写方式在参数类型已知的情况下有效:
val fun = _ *2 //错误,无法推断
val fun = (_:Double)*3 // ok
3.一些有用的高阶函数
- (1 to 9).map(10* _).foreach(print)
map()将一个函数应用到某个集合的所有元素并返回结果,foreach()将所有元素遍历,用print打印。 - (1 to 9).filter(_%2==0) //2 4 6 8
过滤可以被2 整除的数。 - (1 to 9).reduce(_ + _) //带两个参数的函数
遍历从左到右的所有元素,等同于(((1+2)+3)+4)+…+9,每次计算的结果赋给左边的参数,后面的赋给右边,reduce默认为reduceLeft,与reduceRight相反。 - “Alice has a pretty face”.split(" ").sortWith(_.length < _.length)
输出一个按长度递增的Array数组:(a, has, face, Alice, pretty) - (1 to n).foldLeft(1)(_ * _) //120
输出1-n的阶乘,若n<=1,则返回1,使用柯里化的高阶函数。
4.柯里化
指将原来接受两个参数的函数变成接收一个参数函数的过程:
两个参数:
def mul(x:Int,y:Int) = x*y
一个参数,返回一个函数:
def mul(x:Int) = (y:Int) => x*y
要计算两个数二点乘积,你需要调用:
mul (2)(3) //6
最终形态——scala支持如下的简写来定义这样的柯里化函数:
def mul(x:Int)(y:Int)=x*y
//调用
mul(2)(3)