在函数式编程语言中,函数是“头等公民”,可以像任何其他数据类型一样被传递和操作。因为Scala混合了面向对象和函数式的特性,所以对Scala来说,函数是“头等公民”。
作为值的函数
|
importscala.math._
valfun=ceil_ // _将ceil方法转成了函数
|
在Scala中,无法直接操纵方法,只能直接操纵函数,所以需要使用_。
fun的类型是(Double)=>Double,意为接受Double参数并返回Double的函数。能够对fun做的有:调用,传递。
|
valnum=3.14
fun(num) // 返回4.0,调用fun
Array(3.14,1.42,2.0).map(fun) //返回Array(4.0, 2.0, 2.0),将fun作为变量传递
|
匿名函数
函数不一定需要名称:
|
(x:Double)=>3*x // 该匿名函数将传给它的参数乘3
|
可以将匿名函数赋值给变量,也可以当参数传递。
带函数参数的函数
如何实现一个接受另一个函数为参数的函数:
|
defvalueAtOneQuarter(f:(Double)=>Double)=f(0.25)
|
该函数的类型是: ((Double) => Double) => Double。
还有可以返回一个函数的函数:
|
defmulBy(factor:Double)=(x:Double)=>factor*x
// mulBy可以产出任何两个数相乘的函数
valquintuple=mulBy(5) // (x: Double) => 5 * x
quintuple(20) // 5 * 20
|
这样接受函数参数,或者是返回函数的函数,被称为高阶函数(higher-order function)。
参数(类型)推断
前面有定义高阶函数 def valueAtOneQuarter(f: (Double) => Double) = f(0.25),因为已知参数的类型,所以Scala会尽可能推断出类型,在传入参数时,可以省掉一些内容。
|
valueAtOneQuarter((x:Double)=>3*x) // 完整写法
valueAtOneQuarter((x)=>3*x) // 已知参数类型,可以省掉Double
valueAtOneQuarter(x=>3*x) // 只有一个参数时,可以省去()
valueAtOneQuarter(3*_) // 参数只在右侧出现一次,可以用_替换
|
闭包
闭包(closure)这个概念,虽然差不多能懂,但解释不清楚的感觉,参考一下闭包的维基百科。
SAM转换
在Scala中,要某个函数做某件事时,会传一个函数参数给它。而在Java中,并不支持传送参数。通常Java的实现方式是将动作放在一个实现某接口的类中,然后将该类的一个实例传递给另一个方法。很多时候,这些接口只有单个抽象方法(single abstract method),在Java中被称为SAM类型。
举例,点击一个按钮时,增加一个计数器:
|
varcounter=0
valbutton=newJButton("Increment")
button.addActionListener(newActionListener{
overridedefactionPerformed(event:ActionEvent){
count+=1
}
})
|
这是非常常见的,给按钮添加监听器的代码。其实只要给addActionListener传一个函数参数,也就能够实现一样的功能了。
|
button.addActionListener((event:ActionEvent)=>counter+=1)
|
为了使这个语法真的生效,需要提供一个隐式转换。隐式转换将在21章详述。下面是简单的示例:
|
implicitdefmakeAction(action:(ActionEvent)=>Unit)=
newActionListener{
overridedefactionPerformed(event:ActionEvent){action(event)}
}
|
将这个函数和界面代码放在一起,就可以在所有预期ActionListener对象的地方,传入(ActionEvent)=>Unit函数参数。
从上面的代码可以看出,隐式转换就是将一种类型自动转换成另外一种类型,是个函数。因为在Scala中,函数是头等公民,所以隐式转换的作用也大大放大了。
柯里化(Currying)
柯里化的概念也请参考维基百科。
柯里化指的是将原来接受两个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数作为参数的函数。
|
defmulOneAtATime(x:Int)=(y:Int)=>x*y
// 计算两个数的乘积
mulOneAtATime(6)(7)
// 多参数的写法
defmul(x:Int,y:Int)=x*y
|
mulOneAtATime(6)返回的是函数(y: Int)=>6*y,再将这个函数应用到7,最终得到结果。
柯里化函数可以在Scala中简写:
|
defmulOneAtATime(x:Int)(y:Int)=x*y
|
多参数是个虚饰,不是编程语言的根本性的特质。
可以利用柯里化把某个函数参数单独拎出来,提供更多用于类型推断的信息。
|
vala=Array("Hello","World")
valb=Array("hello","world")
a.corresponds(b)(_.equalsIgnoreCase(_))
|
corresponds的类型声明如下:
|
defcorresponds[B](that:GenSeq[B])(p:(T,B)⇒Boolean):Boolean
|
方法有两个参数,that序列和f函数,其中f函数有两个参数,第二个参数类型是与that序列一致的。因为使用了柯里化,我们可以省去第二个参数中B的类型,因为从that序列中推断出B的类型。于是,_equalsIgnoreCase(_)这个简写就符合参数的要求了。
控制抽象
Scala中,可以将一系列语句归组成不带参数也没有返回值的函数。
|
defrunInThread(block:()=>Unit){
newThread{
overridedefrun(){block()}
}.start()
}
// 调用
runInThread{()=>println("Hi");Thread.sleep(10000);println("Bye")}
|
可以去掉调用中的()=>,在参数声明和调用该函数参数的地方略去(),保留=>。
|
defrunInThread(block:=>Unit){
newThread{
overridedefrun(){block}
}.start()
}
// 调用
runInThread{println("Hi");Thread.sleep(10000);println("Bye")}
|
Scala程序员可以构建控制抽象:看上去像是编程语言关键字的函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
defuntil(condition:=>Boolean)(block:=>Unit){
if(!condition){
block
until(condition)(block)
}
}
// 使用
varx=10
until(x==0){
x-=1
println(x)
}
|
这样的函数参数专业术语叫做换名调用参数(常规的参数叫换值调用参数)。函数在调用时,换名调用参数的表达式不会被求值,表达式会被当做参数传递下去。
return表达式
一般不需要使用return来返回函数值。但是return可以用来从一个匿名函数中返回值给包含这个匿名函数的带名函数,对于控制抽象来说是很有用的。如果要在带名参数中使用return,需要在定义中给出返回类型。
|
defindexOf(str:String,ch:Char):Int={
vari=0
util(i==str.length){
if(str(i)==str.length)returni
i+=1
}
return-1
}
|
在这里,util这个抽象控制中的return语句,会使外部的带名函数indexOf终止并且返回i的值。
这里控制流程的实现依赖于在匿名函数中return表达式抛出的特殊异常。如果这个异常在被送往带名函数前被捕获,那么就无法为带名函数返回值了,这一点需要注意
相关推荐
详细讲解Scala中的高阶函数部分,具体实例剖析Scala中高阶函数的意义所在,对控制抽象进行了详细的说明,参考书籍《快学Scala》、《Programming in Scala》
函数式编程是从编程方式(范式)的角度来谈的,可以这样理解:函数式编程把函数当作一等公民,充分利用函数、只是函数的多种使用方式,在Scala中,函数是一等公民,像变量一样,既可以作为函数的参数使用,也可以将...
尽管函数式编程在近十多年用得越来越多,但市面上介绍其高阶特性的书却并不多。这本书在这方面是个重要的补充,它不仅仅面向 Scala 程序员,同样面向用任何编程语言开发的程序员,只要你充满好奇心。 ——挖财网...
Scala也是一种函数式...Scala提供了轻量级的语法用以定义匿名函数,支持高阶函数,允许嵌套多层函数,并支持柯里化 。Scala的Case Class及其内置的模式匹配相当于函数式编程语言中常用的代数类型(Algebraic Type)。
Scala和Spark大数据分析函数式编程、数据流和机器学习
最好的scala 学习课件,最好的scala 学习课件,学习spark必备
IDEA集成scala(csdn)————程序
英文原版 scala函数式编程 function programming in scala
Scala 函数嵌套我们可以在 Scala 函数内定义函数,定义在函数内的函数称之为局部函数。
函数式编程(FP)是一种...《Scala函数式编程》是针对希望学习FP并将它应用于日常编码中的程序员而写的,内容包括:函数式编程的概念;函数式编程相关的各种“为什么”和“怎么做”;如何编写多核程序;练习和检测。
目录如下 Scala简介&快速入门 基础语法 变量 数据类型 流程控制 操作符重载 模式匹配 函数式编程基础 函数式编程说明 ... 高阶函数 闭包closure 柯里化函数 控制抽象 递归高级 Akka 介绍
该压缩包包含scala学习教程的入门到深入,包括入门级,以及scala的设计、编程模式等各种scala学习文档
Scala学习笔记,大全笔记
SCALA 学习手册 2016.02
学习scala笔记,学习scala笔记,学习scala笔记,学习scala笔记,学习scala笔记,
scala连接redis哨兵模式 demo 使用scala的redis库(csdn)————程序
Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。 Scala 运行在Java虚拟机上,并兼容现有的Java程序。 Scala 源代码被编译成Java字节码,所以它可以运行于...
scala是一种基于JVM的面向对象的函数编程,scala编程相对于...2:函数式编程,柯里化函数,匿名函数,高阶函数等。 3:代码行简单。 4:支持并发控制,Actor Model机制 5:目前比较流行的kafka,spark均由scala开发。