作为值的函数
函数和变量作为Scala语言的一等功明,函数可以直接赋值给变量;
object functionalProgramming {
def main(args: Array[String]): Unit = {
val hiData = hiBigData _
hiData("Spark")
}
def hiBigData(name: String){
println("Hi, " + name)
}
}
匿名函数
函数更常用的方式是匿名函数,定义的时候只需要说明输入参数的类型和函数体即可,无需名称。
object functionalProgramming {
def main(args: Array[String]): Unit = {
val f = (name: String ) => println("Hi, " + name)
f("Kafka")
}
def hiBigData(name: String){
println("Hi, " + name)
}
}
代函数参数的函数
函数可以作为参数直接传递给函数,这极大地简化了编程的语法
为什么?
- 以前Java的方式是new出一个接口实例,并且在接口实例的回调方法中来实现业务逻辑,现在是直接把回调方法callback,传递给我的函数,且在函数体中直接使用,这毫无疑问地简化了代码的编写,提升了开发效率;
- 这种方式非常方便编写负责的业务逻辑和控制逻辑,富裕图计算、机器学习、深度学习等至关重要
object functionalProgramming {
def main(args: Array[String]): Unit = {
def getName(func: (String) => Unit,name:String ){
func(name)
}
getName(f,"Scala")
val mutiplrArray = Array(1 to 10 : _*).map{ (item:Int) => 2* item }.foreach{ x => println(x)}
}
def hiBigData(name: String){
println("Hi, " + name)
}
}
闭包
函数的返回值可以是函数,这表明Scala的函数实现了闭包!
Scala闭包的内幕是:Scala的函数背后是类和对象,so Scala的参数作为了对象的成员,so 后续可以继续访问,这就是Scala实现闭包的原理内幕!
def mulBy(factor:Double) = (x:Double) => factor * x
val triple = mulBy(3)
val half = mulBy(0.5)
println(triple(14) + " " + half(14)) //打印结果为42 7
- mulBy的首次调用将参数变量factor设为3。该变量在(x:Double) => factor * x函数的函数体内被引用,该函数被存入triple,此时triple返回值是“val triple: Double => Double”。然后参数变量factor从运行时的栈上被弹出。
- 接下来mulBy再次被调用,这次factor被设置为0.5。该变量在(x:Double) => factor * x函数的函数体内被引用。
- 这样每个返回的函数都有自己的factor设置。
- 这样一个函数被称作闭包(closure)。闭包由代码和代码用到的任何非局部变量定义构成。
柯里化
柯里化(currying)指将原来的接受两个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数作为参数的函数。
下面先给出一个普通的非柯里化的函数定义,实现一个加法函数:
def plainOldSum(x:Int,y:Int) = x + y
plainOldSum(1,2) //结果为3
下面在使用“柯里化”技术来定义这个加法函数,原来函数使用一个参数列表,“柯里化”把函数定义为多个参数列表:
def curriedSum(x:Int)(y:Int) = x + y
curriedSum (1)(2) //结果为3
当调用curriedSum (1)(2)时,实际上是依次调用两个普通函数(非柯里化函数),
- 第一次调用使用一个参数x,返回一个函数类型的值
- 第二次使用参数y调用这个函数类型的值
使用下面两个分开的定义在模拟curriedSum柯里化函数:
首先定义第一个函数:
def first(x:Int) = (y:Int) => x + y
然后我们使用参数1调用这个函数来生成第二个函数(闭包的概念)。
val second=first(1)
println(second(2)) //输出结果是3
first,second的定义演示了柯里化函数的调用过程,它们本身和curriedSum 没有任何关系,但是我们可以使用curriedSum 来定义second,如下:
val onePlus = curriedSum(1)_
下划线“_” 作为第二参数列表的占位符, 这个定义的返回值为一个函数,当调用时会给调用的参数加一。
onePlus(2)
通过柯里化,你还可以定义多个类似onePlus的函数,比如twoPlus
val twoPlus = curriedSum(2) _
println(twoPlus(2))
在“闭包”那一节中的代码可改写为
def mulBy(factor:Double) = (x:Double) => factor * x
println(mulBy(3)(14) + " " + mulBy(0.5)(14))
复杂的函数式编程中经常使用,可以维护变量在内存中的状态,且实现返回函数的链式功能,可以实现非常复杂的算法和逻辑