Scala混合了面向对象和函数式的特性,我们通常将可以作为参数传递到方法中的表达式叫做函数。在函数式编程语言中,函数是“头等公民”,高阶函数包含:作为值的函数、匿名函数、闭包、柯里化等等。
可以像任何其他数据类型一样被传递和操作的函数,每当你想要给算法传入具体动作时,这个特性就会变得非常有用。
scala>val arr = Array(1,2,3,4,5)
arr:Array[Int] = Array(1,2,3,4,5)
//定义一个函数,并将函数赋值给变量fun1
scala> val fun1 = (x:Int) => x * 2
fun1:Int => Int = <function1>
//将函数作为参数传入map方法中
scala>arr.map(fun1)
res0:Array[Int] = Array(2,4,6,8,10)
定义函数时格式:val 变量名 = (输入参数类型和个数)=> 函数实现和返回值类型 “=” 表示将函数赋给一个变量。
=> 左边表示输入参数名称、类型和个数,右边表示函数的实现和返回值类型。
在Scala中,你不需要给每一个函数命名,没有将函数赋值给变量的函叫做匿名函数。
scala>arr.map((x:Int) => x * 2)
res2:Array[Int] = Array(2,4,6,8,10)
由于Scala可以自动推断出参数的类型,因此可以写得更精简些。
scala>arr.map(x => x * 2)
res3:Array[Int] = Array(2,4,6,8,10)
神器的下划线,这样更精简
scala>arr.map(_*2)
res4:Array[Int] = Array(2,4,6,8,10)
柯里化(Currying):将接收多个参数的方法,转换为接收一个参数的函数的过程 => 返回值是一个函数,参数就是其余参数,而且第一个参数的值会累计在此函数中。
//一个比较奇怪的方法,看起来即像方法又像函数
scala> def m(x:Int) = (y:Int) => x * y
m:(x:Int)Int => Int
//将一个参数3传进函数后,彻底变成一个函数.val func = (y:Int) => 3 * y
scala> val func = m(3)
func:Int => Int = <function1>
//然后调用这个函数并传递第二个参数,得到最终结果
scala>func(5)
res3:Int - 15
//在Scala中这样的函数可以简写成def m(x:Int)(y:Int) = x * y
scala>m(3)(5)
res4:Int = 15
scala> def plainOldSum(x:Int,y:Int) = x + y
plainOldSum:(x:Int,y:Int)Int
scala>plainOldSum(1,2)
res0:Int = 3
scala>def curriedSum(x:Int)(y:Int) = x + y
curriedSum:(x:Int)(y:Int) Int
scala>curriedSum(1)(2)
res1:Int = 3
当你调用curriedSum(1)(2)时,实际上是依次调用两个普通函数(非柯里化函数),第一次调用使用一个参数x,返回一个函数类型的值;第二次使用参数y调用这个函数类型的值。
//首先定义第一个函数:
scala> def first(x:Int)=(y:Int)=>x+y
first: (x: Int)Int => Int
//然后我们使用参数1调用这个函数来生成第二个函数:
scala> val second =first(1)
second: Int => Int = <function1>
scala> second(2)
res2: Int = 3
scala> val onePlus=curriedSum(1)_
onePlus: Int => Int = <function1>
//下划线“_” 作为第二参数列表的占位符, 这个定义的返回值为一个函数,当调用时会给调用的参数加一。
scala> onePlus(2)
res3: Int = 3
//调用生成的函数,给函数传入参数,即可得到我们想要的结果。
scala柯里化风格的使用可以简化主函数的复杂度,提高主函数的自闭性,提高功能上的可扩展性、灵活性。可以编写出更加抽象,功能化和高效的函数式代码。
就是函数的返回值依赖于函数之外的参数
/**
* scala中的闭包
* 闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。
*/
object ClosureDemo {
def main(args: Array[String]): Unit = {
val y=10
//变量y不处于其有效作用域时,函数还能够对变量进行访问
val add=(x:Int)=>{
x+y
}
//在add中有两个变量:x和y。其中的一个x是函数的形式参数,
//在add方法被调用时,x被赋予一个新的值。
// 然而,y不是形式参数,而是自由变量
println(add(5)) // 结果15
}
}