您的位置:首页 > 其它

scala学习笔记-高阶函数

2017-11-27 22:40 239 查看


作为值的函数

在scala中,函数是头等公民,就和数字一样。可以在变量中存放函数:
val fun=ceil_

将fun设为ceil函数,ceil函数后的_意味着你确实指的是这个函数,而不是碰巧忘记了给它送参数
说明:从技术上讲,)将ceil方法转换成了函数。在scala中,你无法直接操纵方法,而只能直接操纵函数,方法不能作为单独的表达式而存在(参数为空的方法除外),而函数可以被调用;存放在变量中,或者作为参数传递给另一个函数


匿名函数

在scala中,不需要给每个函数命名。例如:
(x:Double)=>3*x  //将传递给它的参数乘以3

可以将这个函数存放到变量中:
val triple=(x:Double)=>3*x

这就和用def一样:
def triple(x:Double)=>3*x

但是你不需要给函数命名。也可以直接将它传递给另一个函数:
Array(3.14,2.43,4.52).map((x:Double)=>x*2)  //Array(6.28,4.86,9.04)


带函数参数的函数

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

注意,这里的参数可以是任何接受Double并返回Double的函数。valueAtOneQuarter函数将计算那个函数在0.25位置的值
例如:
valueAtOneQuarter(ceil_)  //1.0  ceil函数的作用是求不小于给定实数的最小整数
valueAtOneQuarter(sqrt) //0.5

valueAtOneQuarter是一个带有单个参数的函数,因为它的类型为:
(参数类型)=>结果类型
因此valueAtOneQuarter的类型为:
((Double)=>Double)=>Double
由于valueAtOneQuarter是一个接受函数参数的函数,因此它被称为高阶函数。
高阶函数也可以产出另一个函数。例如:
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*_)

这种简写方式只在参数类型已知的情况下有效。
val fun=3*_  //错误:无法判断出类型
val fun=3*(_:Double)  //OK
val fun:(Double)=>Double=3*_   //OK,因为给出了fun的类型


闭包

在scala中,你可以在任何作用域内定义函数:包、类甚至是另一个函数或者方法。
例如:
def mulBy(factor:Double)=(x:Double)=>factor*x
考虑如下调用:
val triple=mulBy(3)
val half=mulBy(0.5)
println(triple(14)+ "" +half(14) )  //42 7


柯里化

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

要计算两个数的乘积,你需要调用:
mulOneAtATime(6)(7)

严格讲,mulOneAtATime(6)的结果是函数(y:Int)=>6*y。而这个函数又被应用到7,因此最终得到42
scala支持如下简写来定义这样的柯里化函数:
def mulOneAtATime(x:Int)(y:Int)=x*y


控制抽象

在scala中,可以将一系列语句归组成不带参数也没有返回值的函数。例如:
def runInThread(block:()=>Unit){
new Thread{
override def run(){  block() }
}.start()
}

这段代码以类型为()=>Unit的函数的形式给出。调用该函数:
runInThread{()=>println("Hi"); Thread.sleep(1000);println("Bey")   }

想要在调用中省略()=>,可以使用换名调用表示法:在参数声明和调用该函数参数的地方略去(),但保留=>:
def runInThread(block:=>Unit){
new Thread{
override def run(){  block }
}.start()
}

这样调用代码就变成:
runInThread{ println("Hi"); Thread.sleep(1000);println("Bey")   }

scala程序员可以构建控制抽象:看上去像是编程语言的关键字函数。例如:我们可以实现一个用起来完全像是在使用while语句那样的函数。或者定义一个until语句,工作原理类似while,只不过把条件反过来使用:
def until(condition:=>Boolean){ block:=>Unit){
if(!condition){
block
until(condition)(block)
}
}

以下是如何使用until的:
var x=10
until(x==0){
x-=1
println(x)
}

这样的函数参数叫做换名调用参数


return表达式

scala中,不需要return 语句来返回函数值。函数的返回值就是函数体的值。
可以用return来从一个匿名函数中返回值给包含这个匿名函数的带名函数。这对于控制抽象很有用。例如:
def indexOf(str:String,ch:Char):Int={
var i=0
until(i==str.length){
if(str(i)==ch)  return 1
i +=1
}
reutrn -1
}

这里匿名函数{  if(str(i)==ch)  return 1; i +=1}被传递给until 。当return表达式被执行时,包含它的带名函数indexOf终止并返回给定的值。如果你要在带名函数中使用return的话,则需要给出其返回类型。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息