专栏原创出处: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
最后修改时间: 2/17/2020, 4:43:04 AM