Scala高级特性之高阶函数、作为值的函数、匿名函数、柯里化(Currying)、闭包 25

    xiaoxiao2023-11-07  142

    前言之高阶函数的概念

    Scala混合了面向对象和函数式的特性,我们通常将可以作为参数传递到方法中的表达式叫做函数。在函数式编程语言中,函数是“头等公民”,高阶函数包含:作为值的函数、匿名函数、闭包、柯里化等等。

    1. 作为值的函数

    可以像任何其他数据类型一样被传递和操作的函数,每当你想要给算法传入具体动作时,这个特性就会变得非常有用。

    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 变量名 = (输入参数类型和个数)=> 函数实现和返回值类型 “=” 表示将函数赋给一个变量。 => 左边表示输入参数名称、类型和个数,右边表示函数的实现和返回值类型。

    2. 匿名函数

    在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)

    3. 柯里化(Currying)

    3.1 什么是柯里化

    柯里化(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

    3.2 例子

    一个普通的非柯里化的函数定义,实现一个加法函数: 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 使用curriedSum来定义second scala> val onePlus=curriedSum(1)_ onePlus: Int => Int = <function1> //下划线“_” 作为第二参数列表的占位符, 这个定义的返回值为一个函数,当调用时会给调用的参数加一。 scala> onePlus(2) res3: Int = 3 //调用生成的函数,给函数传入参数,即可得到我们想要的结果。

    3.3 总结

    scala柯里化风格的使用可以简化主函数的复杂度,提高主函数的自闭性,提高功能上的可扩展性、灵活性。可以编写出更加抽象,功能化和高效的函数式代码。

    4. 闭包

    4.1 什么是闭包

    就是函数的返回值依赖于函数之外的参数

    4.2 代码如下

    /** * 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 } }
    最新回复(0)