2021年大数据常用语言Scala(三十七):scala高级用法 高阶函数用法

2021-10-11 15:31:45 浏览数 (1)


高阶函数用法

Scala 混合了面向对象和函数式的特性,在函数式编程语言中,函数是“头等公民”,它和Int、String、Class等其他类型处于同等的地位,可以像其他任何数据类型一样被传递和操作。

高阶函数包含:作为值的函数、匿名函数、闭包、柯里化等等。

作为值的函数

在scala中,函数就像和数字、字符串一样,可以将函数传递给一个方法。我们可以对算法进行封装,然后将具体的动作传递给算法,这种特性很有用。

我们之前学习过List的map方法,它就可以接收一个函数,完成List的转换。

示例:将一个小数列表中的每个元素转换为对应个数的小星星

List(1, 2, 3...) => *, ,

代码:

代码语言:javascript复制
val list = List(1, 2, 3, 4)

// 字符串*方法,表示生成指定数量的字符串
val func_num2star = (num:Int) => "*" * num

print(list.map(func_num2star))

匿名函数

上面的代码,给(num:Int) => "*" * num函数赋值给了一个变量,但是这种写法有一些啰嗦。在scala中,可以不需要给函数赋值给变量,没有赋值给变量的函数就是匿名函数

示例:优化上述代码

代码语言:javascript复制
val list = List(1, 2, 3, 4)

list.map(num => "*" * num).foreach(println)
// 因为此处num变量只使用了一次,而且只是进行简单的计算,所以可以省略参数列表,使用_替代参数
list.map("*" * _).foreach(println)

柯里化(多参数列表)

list.fold(100)(_ _)

柯里化(Currying)允许方法接收多个参数列表的语法特性。

多数用于隐式转换或者在逻辑上划分不同批次的参数用。

特点:参数如果不传递完全,得到一个函数

柯里化过程解析

使用柯里化,让传递匿名函数作为参数的语法更为简洁

示例:编写一个泛型方法,用来完成两个值类型的计算(具体的计算封装到函数中)

代码语言:javascript复制
object CurryingDemo2 {

  // 实现对两个数进行计算的方法
  def calc[A <: AnyVal](x:A, y:A, func_calc:(A, A)=>A) = {
    func_calc(x, y)
  }

  // 柯里化:实现对两个数进行计算
  def calc_carried[A <: AnyVal](x:A, y:A)(func_calc:(A, A)=>A) = {
    func_calc(x, y)
  }

  def main(args: Array[String]): Unit = {
    // 这种写法是不能被简化的,必须要写出函数的定义
    println(calc(10, 10, (x:Int, y:Int)=> x   y))
    println(calc(10.1, 10.2, (x:Double, y:Double)=> x*y))
    
    // 柯里化之后可以快乐地使用下划线了
    println(calc_carried(10, 10)(_   _))
    println(calc_carried(10.1, 10.2)(_ * _))
    println(calc_carried(100.2, 10)(_ - _))
  }
}

闭包

闭包其实就是一个函数,只不过这个函数的返回值依赖于声明在函数外部的变量。

可以简单认为,就是可以访问不在当前作用域范围的一个函数。

可以不修改方法体,通过外部变量来控制方法返回结果

示例:定义一个闭包

代码语言:javascript复制
object ClosureDemo {

  def add(x:Int) = {
    val y = 10

    // add返回一个函数,该函数引用了add方法的一个局部变量
    val funcAdd = () => x   y
    funcAdd
  }

  def main(args: Array[String]): Unit = {

    // 调用add方法时,任然可以引用到y的值
    // funcAdd函数就是一个闭包
    println(add(10)())
  }
}

上面的演示只是使用一个普通的int值来做的闭包。 如果依赖的外部变量是一个函数呢?

那就是,无需修改方法体, 修改外部函数就能修改计算逻辑。

0 人点赞