目录
高阶函数用法
作为值的函数
匿名函数
柯里化(多参数列表)
闭包
Scala 混合了面向对象和函数式的特性,在函数式编程语言中,函数是“头等公民”,它和Int、String、Class等其他类型处于同等的地位,可以像其他任何数据类型一样被传递和操作。
高阶函数包含:作为值的函数、匿名函数、闭包、柯里化等等。
在scala中,函数就像和数字、字符串一样,可以将函数传递给一个方法。我们可以对算法进行封装,然后将具体的动作传递给算法,这种特性很有用。
我们之前学习过List的map方法,它就可以接收一个函数,完成List的转换。
示例:将一个小数列表中的每个元素转换为对应个数的小星星
List(1, 2, 3...) => *, \, \
代码:
val list = List(1, 2, 3, 4)
// 字符串*方法,表示生成指定数量的字符串
val func_num2star = (num:Int) => "*" * num
print(list.map(func_num2star))
上面的代码,给(num:Int) => "*" * num函数赋值给了一个变量,但是这种写法有一些啰嗦。在scala中,可以不需要给函数赋值给变量,没有赋值给变量的函数就是匿名函数
示例:优化上述代码
val list = List(1, 2, 3, 4)
list.map(num => "*" * num).foreach(println)
// 因为此处num变量只使用了一次,而且只是进行简单的计算,所以可以省略参数列表,使用_替代参数
list.map("*" * _).foreach(println)
list.fold(100)(_ + _)
柯里化(Currying)允许方法接收多个参数列表的语法特性。
多数用于隐式转换或者在逻辑上划分不同批次的参数用。
特点:参数如果不传递完全,得到一个函数
柯里化过程解析
使用柯里化,让传递匿名函数作为参数的语法更为简洁
示例:编写一个泛型方法,用来完成两个值类型的计算(具体的计算封装到函数中)
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)(_ - _))
}
}
闭包其实就是一个函数,只不过这个函数的返回值依赖于声明在函数外部的变量。
可以简单认为,就是可以访问不在当前作用域范围的一个函数。
可以不修改方法体,通过外部变量来控制方法返回结果
示例:定义一个闭包
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值来做的闭包。 如果依赖的外部变量是一个函数呢?
那就是,无需修改方法体, 修改外部函数就能修改计算逻辑。