高阶函数

在函数式编程中,函数可以像任何其他数据类型一样被传递和操作。把明细动作包在函数中作为参数传入。

这篇文章包含如下主要内容:

1.可以创建匿名函数,并把匿名函数交给其他函数。

2.许多集合方法都接受函数参数,将函数应用到集合中的值。

3.可以创建操作代码块的函数,它们看上去像是内建的控制语句。


1.作为值的函数:

可以在变量中存放函数。并且可以对函数做两件事情:

(1)调用它

(2)传递它,存在一个变量中,或者作为参数传递给另一个函数。

下面的例子展示了对函数做的上边这2种操作:

    /**
     * 1.作为值的函数,可以对函数做两件事情:(1)调用它;(2)传递它,将函数传递给另外一个函数。
     */
    import scala.math._
    val pi = 3.14
    //将函数传递给一个变量, 可以写成:ceil _ 或者 ceil(_)
    val fun = ceil _
    //调用函数
    println(fun(pi))
    //传递函数
    val output_array = Array(1.34,9.984,23.4).map { fun }
    println(output_array.mkString(","))


2.匿名函数:

在scala中,不需要为每一个函数命名,下面是一个匿名函数。 可以将匿名函数传给变量,或者直接将匿名函数传给另外一个函数。

    /**
     * 2.匿名函数
     */
    //把匿名函数传给一个变量
    val noname_func = (x:Double) => 3*x
    //把匿名函数传给另外一个函数
    val output_array2 = Array(1.34,9.984,23.4).map { (x:Double) => 3*x }
    println(noname_func(2.32))
    println(output_array2.mkString(","))


3.带函数参数的函数:

实现接受另一个函数作为参数的函数。如下面定义的函数:

def valueAtOneQuarter( f:(Double) => Double ) = f(0.25)

函数valueAtOneQuarter的参数是任何可以接受Double并返回Double的函数。valueAtOneQuarter的参数类型是 一个带有单个参数的函数,写作 (参数类型) => 结果类型 。

valueAtOneQuarter的类型可以写成是:((Double) => Double) => Double 


由于valueAtOneQuarter是一个接受函数参数的函数,因此被称为“高阶函数”(higher-order function)。

高阶函数可以产生另一个函数。例如下边例子中的multBy函数:

    /**
     * 3.带函数参数的函数
     * 写一个能产出能够乘以任何数额的函数
     * 
     */
    println("------------------测试:带函数参数的函数-----------------------")
    //这里的参数可以是任何接收Double并返回Double的函数。
    def valueAtOneQuarter( f:(Double) => Double ) = f(0.25)
    def multBy(factor:Double) = (x:Double) => x*factor
    val testmul = multBy(4)
    println(testmul(8))

我们可以分析出multBy函数的类型是:

(Double) => ((Double) => Double)


4.参数推断:

当你把一个匿名函数传给另一个函数或方法时,Scala会推断出类型信息。

valueAtOneQuarter( (x:Double) => 3*x )

由于Scala可以推断出传给valueAtOneQuarter函数的参数类型是: (Double) => Double ,所以:Double完全可以省略。简化成:

valueAtOneQuarter( (x) => 3*x )

当匿名函数的参数只有一个时,可以省略括号,那么可以进一步简化为:

valueAtOneQuarter( x => 3*x )

如果参数在=>右侧只出现一次,可以用_替换掉它,进一步简化为:

valueAtOneQuarter(3*_)


5.一些常用的高阶函数:

(1) map函数:将函数应用到集合的每一个元素,并返回结果。

(2) foreach函数:foreach 和 map 很像,只不过它的函数不返回任何值。foreach只是简单地将函数应用到每一个元素。

(3) filter函数:输出所有匹配某个特定条件的元素。

(4) reduceLeft函数: 接受一个二元的函数(即:带有2个参数的函数),并将它应用到序列中的所有元素,从左到右。它和reduce的区别是,reduceLeft顺序是固定的(从左到右),但是reduce是没有顺序的(随机的)。

下面代码包含以上4个函数:

    /**
     * 4.一些常用的高阶函数的使用
     */
    println("------------------测试:一些常用的高阶函数的使用-----------------------")
    //将1到9的一个集合每个都乘3
    println(1.to(9).map{ 3*_ })
    //foreach使用
    1.to(9).map("*" * _).foreach{println _}
    //filter只取符合条件的值
    println(1.to(9).filter {_ % 2 == 0 })   // 或者filter{ x => x % 2 == 0 }
   //reduceLeft接收一个二元函数,两个下划线分别是2个参数。
    println(1.to(9).reduceLeft(_ + _))


6 .闭包:

对于返回的2个函数:trible 和 half ,它们都有自己各自的设置。trible的factor是3,half的factor是0.5。

那么对于multBy函数,每一个它返回的函数都有各自的factor设置,这样的函数叫做闭包。这些函数实际是以类的方式实现的,该类有一个实例变量factor和一个包含了函数体的apply方法。

    /**
     * 5.闭包
     * 
     */
     println("------------------测试:闭包-----------------------")
     val trible = multBy(3)
     val half = multBy(0.5)
     println(trible(18) + " " + half(18))


7.柯里化:

柯里化:指的是将原来接受2个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数作为参数的函数。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章