Scala专题系列(七):高阶函数

2022-04-18 13:59:58 浏览数 (1)

在第一篇章中,介绍了Scala面向对象和函数式编程的特性,在函数式编程中,函数式头等公民,可以像任何其它数据类型一样被传递和操作.在函数式编程中,我们只需要将逻辑包在函数当中作为参数传入即可.

1 : 把函数当做参数

在Scala中,函数式"头等公民",我们可以在变量中存放函数

val num = 2.2 val fun = scala.math.ceil _

在上述代码中将num设为2.2, fun设为一个ceil函数, scala.math.ceil 函数后的 _ 意味着指定的这个是函数

之后,我们可以这样来调用

val result = fun(num)

在这里,fun是一个包含函数的变量,而不是一个固定的函数

同时,我们也可以将函数fun当做参数传递给另一个函数

Array(2.2,1.3,2.1).map(fun)

map方法接收一个函数参数,将它应用到数组中的所有值,然后返回结果中的数组.

2 : 匿名函数

所谓匿名函数,就是指没有函数的声明,只有函数体.比如:

(x:Doubule) => 3 * x

上面就是一个匿名函数,参数为x,该函数将它的参数乘以3

也可以将这个函数存放在变量中

val triple = (x:Double) => 3 * x

其实就是下面函数的一个变体

def triple(x:Double) = 3 * x

只是不需要给函数命名

接下来看一下把函数当做参数.

比如:

def getValue(f:(Double) => Double) = f(1.2)

在上面的方法中,getValue函数接收一个参数是任何Double类型并返回Double的函数,然后将1.2传入参数中进行计算

getValue(scala.math.ceil _) // 2

因为getValue是一个接收函数参数的函数,因此它被称作高阶函数

高阶函数也可以产出另一个函数,比如:

def mulBy(f:double) = (x:Double) => f * 3

mulBy(2) 返回的函数(x:Double) => 3*x 那么

val quintuple = mylBy(3)

quintUple(20) // 结果就是 60 3 * 20

还可以更加简化上面的操作

比如上面的函数我们可以改为:

triple(f => 3 * x) , scala会帮助我们推断出参数的类型.

再进一步,还可以赞精简一下我们可以用_替换它.

triple(3 * _) // 如果参数在 => 右侧只出现一次,就可以用_替换它

将函数赋值给另一个函数

val fun = 3 * (_:Double)

val fun : (Double) => Double = 3 * _

3 : 闭包操作

在Scala中,我们可以在任何作用域内定义函数,在函数体内,你可以访问到相应作用域内的任何变量.,比如:

def mulBy(f:Double) = (x:Double) => f * x

如下调用

val triple = mulBy(2)

println(triple(2)) // 打印结果为4

接下来复盘一下:

1 : mulBy首次调用将参数变量f赋值为2,该变量在(x:Double) => f

*x 函数体内被引用,该函数被存入了triple

上面的函数就被称之为闭包,闭包由代码和代码用到的任何非局部变量定义构成.这些函数实际上是以类的对象方式实现的,该类有一个实例变量f和一个包含了函数体的apply方法.

4 : 柯里化 (currying)

柯里化,指的是将原来接收两个参数的函数编程新的接受一个参数的函数的过程.新的函数返回一个以原有第二个参数作为参数的函数

实例:

def mul(x:Int,y:Int) = x * y

接下来,函数接受一个参数,生成另一个接受单个参数的函数

def mulOnetoTime(x:Int) = (y:Int) => x *y

要结算两个数的乘积,需要调用

mulOnetoTime(2)(3)

上面的函数可以简写为:

def mulonetoTime(x:Int)(y:Int) = x*y

0 人点赞