Scala快速入门-高阶函数

By timebusker on January 8, 2018

知识点

  • 作为值的函数
  • 创建匿名函数
  • 带函数参数的函数
  • 闭包
  • 柯里化

函数

  • 在Scala中,函数是“头等公民”,可以在变量中存放函数
scala> def fun(msg: String) {println(msg)}
fun: (msg: String)Unit

scala> val f = fun
<console>:8: error: missing arguments for method fun;
follow this method with `_' if you want to treat it as a partially applied function
       val f = fun
               ^

scala> val f = fun _
f: String => Unit = <function1>

scala> f("Yezhiwei")
Yezhiwei

函数后面的 _ 意味着指的是这个函数

  • 作为参数传递给另一个函数
scala> Array("Hello", "Scala").map(f)
Hello
Scala
res2: Array[Unit] = Array((), ())

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

  • 在Scala中,不需要给每一个函数命名,匿名函数
scala> (x: Double) => 3 * x
res3: Double => Double = <function1>
  • 在Scala中,可以将上面的函数放到变量中
scala> val triple = (x: Double) => 3 * x
triple: Double => Double = <function1>

与def一样
def triple = (x: Double) = 3 * x

  • 可以将匿名函数直接传递给另一个函数
scala> Array(3.14, 1.42).map((x: Double) => 3 * x)
res4: Array[Double] = Array(9.42, 4.26)
  • 带函数参数的函数,如实现接受另一个Double并且返回Double的函数
scala> def fun(f: (Double) => Double) = f(0.25)
fun: (f: Double => Double)Double

scala> import scala.math._
import scala.math._

scala> fun(ceil _)
res12: Double = 1.0

scala> fun(sqrt _)
res13: Double = 0.5

///////////

scala> def mulBy(factor: Double) = (x: Double) => factor * x
mulBy: (factor: Double)Double => Double

scala> val q = mulBy(5)
q: Double => Double = <function1>

scala> q(20)
res14: Double = 100.0

// val q = mulBy(5) 相当于 val q = (x: Double) => 5 * x
  • 将一个匿名函数传递给另一个函数或方法时,Scala会尽可能推断出类型信息
scala> def fun(f: (Double) => Double) = f(0.25)
fun: (f: Double => Double)Double

scala> fun((x: Double) => 3 * x)
res16: Double = 0.75

// 由于fun方法知道会传入一个类型为(Double) => Double的函数,可以简单地写成

scala> fun((x) => 3 * x)
res17: Double = 0.75

// 对于只有一个参数的函数,可以省略参数外围的()

scala> fun(x => 3 * x)
res18: Double = 0.75

// 如果参数在=>右侧只出现一次,可以用_替换掉它

scala> fun(3 * _)
res19: Double = 0.75
  • 常用的高阶函数
scala> (1 to 9).map(0.1 * _)
res20: scala.collection.immutable.IndexedSeq[Double] = Vector(0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9)

/////
scala> (1 to 9).map("*" * _).foreach(println _)
*
**
***
****
*****
******
*******
********
*********

/////
scala> (1 to 9).filter(_ % 2 == 0)
res23: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8)

///// 相当于1 * 2 * 3 * 4 ... * 9
scala> (1 to 9).reduceLeft(_ * _)
res0: Int = 362880

...

闭包

  • 闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。
  • 闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另外一个函数。
scala> def mulBy(factor: Double) = (x: Double) => factor * x
mulBy: (factor: Double)Double => Double

scala> val triple = mulBy(3)
triple: Double => Double = <function1>

scala> val half = mulBy(0.5)
half: Double => Double = <function1>

scala> println(triple(14) + " " + half(14))
42.0 7.0

mulBy的首次调用将参数变量factor设置为3,该变量在(x: Double) => factor * x函数的函数体内被引用,该函数被存入triple。

接下来,mulBy再次被调用,这次factor设置为0.5,该变量在(x: Double) => factor * x函数的函数体被引用,该函数被存入half。

每一个返回的函数都有自己的factor设置,这样一个函数被称做闭包,闭包由代码和代码用到的任何非局变量定义构成。

柯里化

  • 柯里化指的是将原来接收两个参数的函数变成新的接收一个参数的函数的过程。新的函数返回一个以原有第二个参数作为参数的函数
scala> def mul(x: Int, y: Int) = x * y
mul: (x: Int, y: Int)Int

scala> def mulOne(x: Int) = (y: Int) => x * y
mulOne: (x: Int)Int => Int

scala> mulOne(6)(7)
res1: Int = 42

// mulOne(6)的结果是函数(y: Int) => 6 * y,崦这个函数又被应用到7,因此得到42。