1、高阶函数和闭包
1.1、定义函数
1.1.1、匿名函数
1.1.2、函数的各种写法
1.2、高阶函数
高阶函数主要有两种:
1、一种是将一个函数当做另外一个函数的参数(即函数的参数是函数)
2、另外一种是返回值是函数的函数(即函数的返回值是函数)
1.2.1、函数返回值为函数
作为返回值:一个方法的返回结果值是一个函数
1.2.2、函数/方法的参数为函数
作为参数:一个方法的参数不是一个值,而是一个函数,就是一个计算逻辑
简单总结:
函数是 Scala 中的头等公民:
1、 可以作为方法的返回值
2、 可以作为方法的参数
3、 方法也可以被转换为函数,特定场景下自动转换或者通过_手动转换
综合代码:
object Demo009_MethodAndFunction {
// 定义一个方法
// 方法 m2 参数要求是一个函数,函数的参数必须是两个 Int类型
// 返回值类型也是 Int类型
def m1(f: (Int, Int) => Int) : Int = f(2, 6)
// 定义一个需要两个 Int类型参数的方法
def m2(x:Int, y:Int):Int = x + y
// 定义一个计算数据不被写死的方法
def m3(f: (Int, Int) => Int, x:Int, y:Int) : Int = f(x, y)
// 定义一个函数 f1 ,参数是两个 Int类型,返回值是一个 Int类型
val f1 = (x: Int, y: Int) => x + y
// 再定义一个函数 f2
val f2 = (m: Int, n: Int) => m * n
// 定义一个传入函数的函数
val f3 = (f: (Int, Int) => Int, x:Int, y:Int) => f(x, y)
//main方法
def main(args: Array[String]) {
// 调用 m1方法,并传入 f1函数
val r1 = m1(f1)
println(r1)
// 调用 m1方法,并传入 f2函数
val r2 = m1(f2)
println(r2)
// 调用 m3方法, 传入 f1函数
val result1 = m3(f1, 2, 4)
println(result1)
// 调用 m3方法,传入 f2函数
val result2 = m3(f2, 2, 4)
println(result2)
// 调用 m3方法, 传入 m2方法作为参数
println(m3(m2, 2, 4))
// 调用 f3函数, 传入 f1函数
println(f3(f1, 3, 4))
}
}
1.3、闭包
闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。
闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另外一个函数。
完整实例:
在 add_more 中有两个变量:x 和 more。其中的一个 x 是函数的形式参数,在 add_more 函 数被调用时,x 被赋予一个新的值。然而,more 不是形式参数,而是自由变量。这里我们引 入一个自由变量 more,这个变量定义在函数外面。
这样定义的函数变量 add_more 成为一个"闭包",因为它引用到函数外面定义的变量,定义 这个函数的过程是将这个自由变量捕获而构成一个封闭的函数。
像这种运行时确定 more 类型及值的函数称为闭包,more 是个自由变量,在运行时其值和 类型得以确定这是一个由开放(free)到封闭的过程,因此称为闭包
有趣的 Scala 闭包的完整测试:
在上面这种代码情况下,bibao 这个函数中的 sum 变量,只有 bibao 内部的 add_sum 才能访 问。但是 bibao 这个函数的返回值却是 add_sum 这个函数,这个函数使用了 sum 这个变量, 所以使得这个变量在 main 方法中调用 result 函数的时候,其实做到了变量到的访问和修改 了 bibao 函数中定义的变量,所以本质上,闭包就是将函数内部和函数外部的连接起来的桥 梁。但是千万注意,这个 sum 变量会一直驻留内存。
1.4、Scala 柯里化 Curry
在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最 初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果是一个新函数的技术。 有时需要允许他人一会在你的函数上应用一些参数,然后又应用另外的一些参数。例如一个 乘法函数,在一个场景需要选择乘数,而另一个场景需要选择被乘数。所以柯里化函数就是 将多个参数分开写,写在不同的小括号里,而不是在一个小括号中用逗号隔开
示例代码:
object CurryTest {
def multiply(x:Int)(y:Int) = x * y
// 柯里化就是把参数可以分开来,把部分函数参数可以用下划线来代替
def multiply2 = multiply (2)_
// 一个普通的方法,接受两个 Int 类型参数做乘积
def multiply3(x:Int, y:Int) = x * y
def multiply4(x:Int, y:Int=10) = x * y
def multiply5(x:Int)(y:Int=10) = x * y
def main(args: Array[String]):Unit = {
println ( multiply (2)(4))
println ( multiply2 (4))
// 跟柯里化的函数在结果上没有区别,那到底有什么区别呢?
println ( multiply3 (2,4))
println ( multiply4 (4))
println ( multiply5 (4)())
}
}
那柯里化到底有什么作用? ?
降低通用性,提高适用性