Scala函数特性

通常情况下,函数的参数是传值参数;即参数的值在它被传递给函数之前被确定。但是,如果我们需要编写一个接收参数不希望马上计算,直到调用函数内的表达式才进行真正的计算的函数。对于这种情况,Scala提供按名称参数调用函数。

示例代码如下:

结果:

在代码中,如果定义函数的时候,传入参数不是传入的值,而是传入的参数名称(如代码中使用t: => Long而不是t:
Long),在调用该函数时,不会立即执行和参数有关的计算,而是到参数真正使用到的时候才进行计算。

结果说明:主函数调用delayed函数后,并不立即执行参数(time()函数的结果),而是跳过,直接执行delayed函数的第一行,到第二行真正使用到t时,才执行time()函数获取t的值,故有上述结果。

如果将t: => Long改成t: Long,则按照值传递进行计算,结果如下:

此时主函数调用了delayed函数后就直接先执行time()函数获取t的值

另一个示例代码如下:

这里调用了一个log函数,传入的参数中有1/0,按理说应该会报异常,但实际结果却是代码顺利的执行完成。为什么呢?这是因为我们在定义log函数的时候使用了“按名称传递参数”,只有到实际执行参数相关的计算时才会检查是否有异常。而代码中if(logEnable)
println(msg)这一行代码实际根本就不会执行,自然也就不会存在检查异常的问题了

如果将msg: =>String改为msg: String,则执行代码就会报错

因为在执行到log(MSG +1 / 0)这一句时就直接计算了1/0,自然就会报错了

使用“按名称传递参数”方式的优点是:1.减少不必要的计算; 2.减少异常

在正常的函数调用中,调用参数在调用函数中是按其定义时的参数顺序进行一一匹配。如果需要按不同的顺序传递参数,就要使用到scala的一种函数特性——命名参数。

命名参数使用方法很简单,即在调用函数时,指定参数名并进行赋值。示例代码如下:

结果:

从代码和结果中就可以看出使用命名参数的优点:在需要时可以任意的指定函数中某个参数的值,而不必将此参数之前的参数都赋值一遍。

scala同java一样,在定义函数的时候支持接收可变长参数列表,即最后一个参数的可以被重复。示例代码如下:

结果:

在此代码中我们定义函数printInfo接收变长参数列表,其最后一个参数names可以根据实际情况进行传参(这里我们传了3个实参)。注意,函数可变参数只能是该函数的最后一个参数(否则不能识别参数长度,这个应该很好理解)。

printInfo函数被声明的参数类型names: String*实际是数组[字符串]

在scala中,函数是“头等公民”,几乎所有的操作都是以函数形式进行。同样的,能够在变量中存放函数(听上去很神奇吧)。示例如下:

本段代码将ceil函数赋值给fun变量,ceil后面的_表名这是一个函数,而不是碰巧忘记给它传参。

在scala中,不需要为每个函数命名,这种没有命名的函数叫做匿名函数。如何进行匿名函数的定义呢?示例如下:

(x:Double) => 3 * x

这就是一个匿名函数。就好像在scala中能够把函数赋值给变量一样,我们可以把匿名函数赋值给变量:

valtriple = (x: Double) => 3 * x

这样的方式跟使用def定义函数一样:

deftriple(x: Double) = 3 * x

但是好处就是能够不给函数命名,就能直接将它传递给另一个函数。这种方法在使用map、filter等函数时非常常用:

由于scala有可以将函数作为参数传递给函数的特性,故从中引出了一种简单的封装模式——借贷模式。代码示例如下:

在此代码中,我们将BufferedWriter进行了封装,只要调用autoWrite函数,传入适当的参数,就可以完成字符串写入文件,而且不需要关闭BufferedWriter。使用借贷模式是对系统资源操作的封装,为了防止资源不被安全释放,其次用户不用考虑资源来自何处,如何归还等问题,只需要使用就行了。

带函数参数的函数由于是一个接受函数参数的函数,故被称为高阶函数,像之前讲到的map()函数就是高阶函数。如下例所示:

上述代码中,apply函数接受一个函数f作为参数,接受一个Int类型的参数,进行f(v)运算,在下面又给出了f具体的定义(layout函数)。

同样的,高阶函数也可以产出另一个函数(即返回结果为一个函数,而不是某个值或对象),如下例所示:

这里函数rectangle的输出是一个计算矩形周长的函数,矩形长已固定。

在高阶函数中,经常将只需要执行一次的函数定义为匿名函数作为参数传递给高阶函数,就好像map()、filter()等高阶函数中经常能看到使用了匿名函数作为参数。匿名函数在这里有一个特性能够帮助我们写出更容易阅读的函数——参数推断

正常情况下,我们使用匿名函数的方式如下:

即在map函数中定义匿名函数(a: Double) => a *
3,但是由于map函数知道你传入的是一个类型为(Double)=> Double类型的函数,故可以简化为下面的代码:

并且如果匿名函数只有一个参数,则可以省略(),继续简化:

在此基础上,如果参数在=>右边只出现了一次,则可以用_替换它:

柯里化是指将原来接收两个参数的函数变成接收一个参数的函数的过程,新的函数返回一个以原有第二个参数作为参数的函数。是不是有种被绕晕了的感觉,先别急,先看一个示例:

结果:

这里可以看出,柯里化函数与多个参数的函数具有相同的功能,这中间有一个“应用部分函数”,或者叫“偏应用函数”,这个函数multipleOf4表示固定了两个参数中的一个,部分提供了函数mul所需要的参数,而不是全部提供。柯里化函数在理解上比较偏向于这样的逻辑。

那么,为什么要使用柯里化呢?首先,柯里化可以让我们构造出更像原生语句提供的功能的代码(就像我们在上面说的那样);第二点也是更重要的一点,就是函数柯里化后,参数相对独立了,这样就可以对函数的某个参数单独提供更多的类型推断信息。如下例所示:

这里的corresponds函数就是柯里化函数,其定义如下:

使用柯里化后,该函数柯里化后单独对第二个参数进行了更详细的功能定义,丰富了函数的功能

时间: 2024-12-30 23:42:16

Scala函数特性的相关文章

王家林亲传《DT大数据梦工厂》第二讲Scala函数定义、流程控制、异常处理入门

你想了解大数据,你想成为年薪百万吗?那你还等着什么,快点来吧!跟着王家林老师学习spark大数据 第二讲主要讲了Scala函数定义.流程控制.异常处理入门 函数定义: 关键字(def) 函数名称 参数(参数名称:参数类型):返回内容类型  =  { 函数体 } 注意: Unit:空的返回内容 Scala结束语是不需要写分号 下面一代码为例: //不带参数 Object  ScalaBasics{ def doWhile(){ var line = “” do{ line = readLine()

02Scala学习-Scala函数定义、流程控制、异常处理入门实战

一 Scala 函数的定义 按照以下格式定义scala函数. def 函数名称(函数输入参数类型){ //函数的实现提 } 1) 第一个简单的例子 HelloWorld object Test2 { def main(args: Array[String]):Unit = { println("HelloWorld") } } a)可以看到输出语句的结尾没有以“;”结束,因为scala的设计者认为,多大一个字符对开发者来说是痛苦的. 他不太赞成在语句的结束写 “;” , 但你也可以写 

Scala 函数

环境: CentOS 6.3 看例子,说实话. 入门函数: scala> def max(x: Int,y: Int): Int = { | if (x > y) x           //竖线| 是换行是自动显示的,不是代码本身 | else y | } max: (x: Int, y: Int)Int //上面代码敲完后,这行就会自动出来 scala> max(3,6) res3: Int = 6 scala> max(3,1) res4: Int = 3 解析:def   

Scala函数的调用

scala函数分为: 传名调用和传值调用 传名调用: 就是将未计算的参数表达式直接应用到函数内部 传值调用: 先计算参数表达式的值,再应用到函数内部 案例:      object FunctionTest {    def main(args: Array[String]) {         delayed(time());    }    def time() = {       println("获取时间,单位为纳秒")       System.nanoTime   }   

Scala 函数和方法的定义与使用

摘要: 函数是一组一起执行一个任务的语句. 您可以把代码划分到不同的函数中.如何划分代码到不同的函数中是由您来决定的,但在逻辑上,划分通常是根据每个函数执行一个特定的任务来进行的. Scala 有函数和方法,二者在语义上的区别很小.Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量.换句话来说在类中定义的函数即是方法. 我们可以在任何地方定义函数,甚至可以在函数内定义函数(内嵌函数).更重要的一点是 Scala 函数名可以有以下特殊字符:+, ++, ~, &,-, -- , \,

scala函数

函数是一组一起执行任务的语句.可以将代码放到独立的功能.如何划分你的代码不同功能?在逻辑上,通常是让每个函数执行特定的任务. Scala有函数和方法,我们术语说的方法和函数互换用微小的差别.Scala方法是其中有一个名字,签名,任选一些注释,有的字节码,其中如在Scala中函数是可被分配给一个变量的完整对象类的一部分.换句话说,函数,其被定义为某些对象的一个成员,被称为方法. 函数定义可以出现在在源文件的任何地方,Scala允许嵌套函数的定义,那就是其他函数定义的内部函数定义.需要注意的最重要的

[scala] scala 函数 (⑦)

1.scala 函数定义 2.scala 高阶函数 3.匿名函数 4.柯里化 import scala.math._ /** * @author xwolf * @date 2017-04-24 9:57 * @since 1.8 */ class Function { // _ 将round 方法转化为函数 val cel = round _ def add(x:Int,y:Int) = x+y //函数 def f(x : => Int) = x.+(3) def m (r : => Do

Go 函数特性和网络爬虫示例

爬取页面 这篇通过网络爬虫的示例,来了解 Go 语言的递归.多返回值.延迟函数调用.匿名函数等方面的函数特性.首先是爬虫的基础示例,下面两个例子展示通过 net/http 包来爬取页面的内容. 获取一个 URL 下面的程序展示从互联网获取信息,获取URL的内容,然后不加解析地输出: // 输出从 URL 获取的内容 package main import ( "fmt" "io" "net/http" "os" "s

scala高级特性-01

目标一:深入理解高阶函数 高阶函数 1.1概念 Scala混合了面向对象和函数式的特性, 我们通常将可以做为参数传递到方法中的表达式叫做函数. 在函数式编程语言中,函数是"头等公民", 高阶函数包含:作为值的函数.匿名函数.闭包.柯里化等等. 1.2作为值的函数(故名思议:函数的值作为返回值) 1.3匿名函数 在scala中,你不需要给每一个函数命名,没有将函数赋给变量的函数叫做匿名函数 由于scala可以自动推断出参数的类型,所以可以写的精简一些 还记的神奇的下划线吗?这才是终结方式