欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Scala基础(3)- 函数进阶

程序员文章站 2023-12-30 21:16:34
...

匿名函数

函数可以没有名称,可以直接赋值。如果函数有多行表达式组成,就加上大括号。这一点对匿名函数同样适用。

scala> val addOne = (x: Int) => x + 1
addOne: (Int) => Int = <function1>

scala> addOne(1)
res4: Int = 2

注意到Scala中一切都是对象。所以addOne是一个对象。同时它又是个包含一个参数的函数。此时,函数和对象得到了统一。

偏函数应用 (Partial Application)

偏函数应用解决这样的问题:如果我们有函数是多个参数的,我们希望能固定其中某几个参数的值。在Scala中,我们可以这么做

scala> def adder(m: Int, n: Int) = m + n
adder: (m: Int,n: Int)Int
scala> val add2 = adder(2, _:Int)
add2: (Int) => Int = <function1>

scala> add2(3)
res50: Int = 5

函数柯里化(Currying)

偏函数应用不是什么新东西,几乎所有编程语言中都可以简单地实现。但更简洁的实现是柯里化。

你可以这样定义柯里化 函数

scala> def multiply(m: Int)(n: Int): Int = m * n
multiply: (m: Int)(n: Int)Int

也可以对一个已有的函数进行转换。例如之前的adder函数

scala> (adder _).curried
res1: (Int) => (Int) => Int = <function1>

函数柯里化依赖匿名函数,把一个多参数的函数转化为多个单参数的函数连接在一起。这样一来,语意的表达就更加丰富而直观,函数组合也更加灵活。

类型推断

一个应用场景就是类型推断。Scala类库中的foldLeft 就是这样一个例子。

def foldLeft[B](z: B)(op: (B, A) => B): B

List("").foldLeft(0)(_ + _.length)

如果使用普通的多参数函数定义

def foldLeft[B](z: B, op: (B, A) => B): B

那么,你在使用时就必须显示地表明类型。

List("").foldLeft(0, (b: Int, a: String) => a + b.length)
List("").foldLeft[Int](0, _ + _.length)

简化API

另一个currying的应用是简化API。在下面的例子中,你可以使用大括号来传递body,使得API调用层次分明。

def loop[A](n: Int)(body: => A): Unit = (0 until n) foreach (n => body)

loop(2) {
   println("hello!")
}

多阶段计算

如果你的多参数函数的计算实际上是分步骤的,某个步骤只依赖某个参数,比如下面的例子。那么柯里化会更加简单。

def v(t: Double, k: Double): Double = {
   // 只依赖于t
   val ft = f(t)

   g(ft, k)
}

v(1, 1); v(1, 2);
相关标签: scala

上一篇:

下一篇: