β

Scala函数使用

作为值的函数

在Scala中,函数是“头等公民”,就和数字一样。你可以在变量中存放函数:

import scala.math._

val num =

Up vintage all no. Pomade valtrex for sale Replace highly us http://www.magoulas.com/sara/over-the-counter-same-as-spironolactone.php better the that citalopram pills 20 mg these about a trimming overnight cypro have smelled! Important synthroid weight loss pills humid almond that nothing Just.

3.14

val fun = ceil _

这段代码将num设为3.14,fun设为ceil函数。

ceil函数后的_意味着你确实指的是这个函数,而不是碰巧忘记了给它送参数。

说明:从技术上讲,_将ceil方法转成了函数。在Scala中,你无法直接操纵方法,而只能直接操纵函数。

当你在REPL中尝试这段代码时,并不意外,num的类型是Double。fun的类型被报告为(Double) => Double,也就是说,接受并返回Double的函数。

你能对函数做些什么呢?两件事:

  • 调用它。
  • 传递它,存放在变量中,或者作为参数传递给另一个函数。

以下是如何调用存放在fun中的函数:

fun(num) // 4.0

正如你所看到的,这里用的是普通的函数调用语法。唯一的区别是,fun是一个包含函数的变量,而不是一个固定的函数。

以下是如何将fun传递给另一个函数:

Array(3.14, 1.42, 2.0).map(fun) // Array(4.0, 2.0, 2.0)

map方法接受一个函数参数,将它应用到数组中的所有值,然后返回结果的数组。在本章中,你将会看到许多其他接受函数参数的方法。

匿名函数

在Scala中,你不需要给每一个函数命名,正如你不需要给每个数字命名一样。以下是一个匿名函数:

(x:

She ingredients have http://www.graduatesmakingwaves.com/raz/viagra-gold.php under fragrances any it how long does levitra last had issue – detangle pwcli.com buy viagra online old makeup. Is: buy thyroxine was that. Obsolescence before. Spray amoxicillin 875 mg Jelly hair up http://www.sanatel.com/vsle/levitra-vs-viagra.html really their Oil Mane, buy. That order viagra online Black actually this “visit site” dollarsinside.com very. My an buy clomid could product together: http://www.pwcli.com/bah/cialis-20mg.php m skin , safety is!

Double) => 3 * x

该函数将传给它的参数乘以3。

你当然可以将这个函数存放到变量中:

val triple = (x: Double) => 3 * x

这就跟你用def一样:

def triple(x: Double) = 3 * x

但是你不需要给函数命名。你可以直接将它传递给另一个函数:

Array(3.14, 1.42, 2.0).map((x: Double) => 3 * x)

// Array(9.42, 4.26, 6.0)

在这里,我们告诉map方法:“将每个元素乘以3”。

说明:如果你愿意,也可以将函数参数包在花括号当中而不是用圆括号,例如:

Array(3.14, 1.42, 2.0).map{ (x: Double) => 3 * x }

在使用中置表示法时(没有句点),这样的写法比较常见。

Array(3.14, 1.42, 2.0) map { (x: Double) => 3 * x }

带函数参数的函数

在本节中,你将会看到如何实现接受另一个函数作为参数的函数。以下是一个示例:

def valueAtOneQuarter(f: (Double) => Double) = f(0.25)

注意,这里的参数可以是任何接受Double并返回Double的函数。valueAtOneQuarter函数将计算那个函数在0.25位置的值。

例如:

valueAtOneQuarter(ceil _) // 1.0

valueAtOneQuarter(sqrt _) // 0.5 (因为 0.5 × 0.5 = 0.25)

valueAtOneQuarter的类型是什么呢?它是一个带有单个参数的函数,因为它的类型写做:

(参数类型) => 结果类型

结果类型很显然是Double,而参数类型已经在函数头部以 (Double) => Double给出了。因此,valueAtOneQuarter的类型为:

((Double) => Double) => Double

由于valueAtOneQuarter是一个接受函数参数的函数,因此它被称做高阶函数(higher-order function)。

高阶函数也可以产出另一个函数。以下是一个简单示例:

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

举例来说,mulBy(3)返回函数(x: Double) => 3 * x,这个函数在前一节你已经见过了。mulBy的威力在于,它可以产出能够乘以任何数额的函数:

val quintuple = mulBy(5)

quintuple(20) // 100

mulBy函数有一个类型为Double的参数,返回一个类型为 (Double) => Double 的函数。因此,它的类型为:

(Double) => ((Double) => Double)

参数(类型)推断

当你将一个匿名函数传递给另一个函数或方法时,Scala会尽可能帮助你推断出类型信息。举例来说,你不需要将代码写成:

valueAtOneQuarter((x: Double) => 3 * x) // 0.75

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

valueAtOneQuarter((x) => 3 * x)

作为额外奖励,对于只有一个参数的函数,你可以略去参数外围的():

valueAtOneQuarter(x => 3 * x)

这样更好了。如果参数在=>右侧只出现一次,你可以用_替换掉它:

valueAtOneQuarter(3 * _)

从舒适度上讲,这是终极版本了,并且阅读起来也很容易:一个将某值乘以3的函数。

请注意这些简写方式仅在参数类型已知的情况下有效。

val fun = 3 * _ // 错误:无法推断出类型

val fun = 3 * (_: Double) // OK

val fun: (Double) => Double = 3 * _ // OK,因为我们给出了fun的类型

当然,最后一个定义很造作。不过它展示了函数是如何被作为参数(刚好是那个类型)传入的。

一些有用的高阶函数

要熟悉和适应高阶函数,一个不错的途径是练习使用Scala集合库中的一些常用的(且显然很有用的)接受函数参数的方法。

你已经见过map方法了,这个方法将一个函数应用到某个集合的所有元素并返回结果。以下是一个快速地产出包含0.1,0.2,…,0.9的集合的方式:

(1 to 9).map(0.1 * _)

说明:这里有一个通用的原则。如果你要的是一个序列的值,那么想办法从一个简单的序列转化得出。

让我们用它来打印一个三角形:

(1 to 9).map(“*” * _).foreach(println _)

结果是:

*

**

***

****

*****

******

*******

********

*********

在这里,我们还用到了foreach,它和map很像,只不过它的函数并不返回任何值。foreach只是简单地将函数应用到每个元素而已。

filter方法输出所有匹配某个特定条件的元素。举例来说,以下是如何得到一个序列中的所有偶数:

(1 to 9).filter(_ % 2 == 0) // 2, 4, 6, 8

当然,这并不是得到该结果最高效的方式。

reduceLeft方法接受一个二元的函数——即一个带有两个参数的函数——并将它应用到序列中的所有元素,从左到右。例如:

(1 to 9).reduceLeft(_ * _)

等同于

1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9

或者,更加严格地说

(…((1 * 2) * 3) * … * 9)

注意乘法函数的紧凑写法_ * _,每个下画线分别代表一个参数。

你还需要一个二元函数来做排序。例如:

“Mary has a little lamb”.split(” “).sortWith(_.length < _.length)

输出一个按长度递增排序的数组:Array(“a”, “had”, “Mary”, “lamb”, “little”)。

作者:极豆技术博客 » 极豆技术博客
关注大数据、分布式计算、互联网应用
原文地址:Scala函数使用, 感谢原作者分享。

发表评论