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

前言之高阶函数的概念

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
  }
}

你可能感兴趣的:(Scala)