专栏原创出处:github-源笔记文件 (opens new window) ,github-源码 (opens new window),欢迎 Star,转载请附上原文出处链接和本声明。
Scala 编程语言专栏系列笔记,系统性学习可访问个人复盘笔记-技术博客 Scala 编程语言 (opens new window)
# 什么是柯里化
柯里化就是未使用全部的参数列表调用多参数列表的方法时,会得到一个函数,该函数接收前面未使用的参数列表作为其参数。
- 方法可以定义多个参数列表,一个
()
包含的内容即为一个参数列表。
# foldLeft 示例
在 Scala 集合 trait TraversableOnce 定义了 foldLeft。
foldLeft 对一个集合进行运算,将函数 op 应用到初始值 z 和集合从左往右的第一个元素上
然后将函数 op 应用到计算结果和集合的下一个元素上,依次类推,直到计算完集合中的所有元素。
// scala LinearSeqOptimized 中定义的 foldLeft 方法
def foldLeft[B](z: B)(@deprecatedName('f) op: (B, A) => B): B = {
var acc = z
var these = this
while (!these.isEmpty) {
acc = op(acc, these.head)
these = these.tail
}
acc
}
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// 由于 foldLeft 是柯里化方法,有两个参数列表,当只使用第一个参数列表调用该方法时
// 会得到一个函数,该函数以剩余的参数列表作为参数,即 (B, A) => B
// 由于第一个参数列表传入 0,scala 自动推断类型,得到剩余一个参数的类型 (Int, Int) => Int
// 最终返回一个高阶函数,返回的高阶函数的类型为:((Int, Int) => Int) => Int
val fold: ((Int, Int) => Int) => Int = numbers.foldLeft(0)
val res = fold((x, y) => x + y)
print(res) // 55
// 也可以使用所有的参数列表进行柯里化方法的调用
numbers.foldLeft(0)((x, y) => x + y)
// 上述调用可以实现方法的复用,可以在 fold 的基础上定义其他计算过程
val res2 = fold((x, y) => x * y)
// 如果不使用多参数列表,而是采用匿名函数作为参数调用方法,写法更为繁琐
// scala 无法进行类型推断,需要手动指明函数参数的类型
numbers.foldLeft(0, {(m: Int, n: Int) => m + n})
// 使用 scala 的类型推断可以让柯里化方法的调用更为简洁
// 第一个 _ 代表初始值或者该函数运算的结果,第二个 _ 代表集合中的下一个元素
numbers.foldLeft(0)(_ + _)
# 有关 foldLeft 和 foldRight 的所有调用形式
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
numbers.foldLeft(0)((sum, item) => sum + item)
numbers.foldRight(0)((sum, item) => sum + item)
numbers.foldLeft(0)(_+_)
numbers.foldRight(0)(_+_)
(0 /: numbers)(_+_) // foldLeft
(numbers :\ 0)(_+_) // foldRight
# 隐式参数
如果要指定参数列表中的某些参数为隐式 (implicit),应该使用多参数列表。
该隐式参数列表必须为最后一个参数列表。
如果要定义多个隐式参数,这些隐式参数必须在同一个参数列表中,参数列表的开头加一个 implicit 关键字即可。
隐式参数不可以和普通参数定义在同一个参数列表中。
更多介绍请参考 《隐式参数》章节。
def execute(arg: Int)(implicit ec: ExecutionContext) = ???
def execute1(arg: Int)(implicit ec: ExecutionContext, tc: String) = ???
def execute2(arg: Int,implicit ec: ExecutionContext) = ??? // does not compile