通常情况下,函数的參数是传值參数;即參数的值在它被传递给函数之前被确定。可是,假设我们须要编写一个接收參数不希望立即计算。直到调用函数内的表达式才进行真正的计算的函数。

对于这样的情况。Scala提供按名称參数调用函数。

演示样例代码例如以下:

结果:

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

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

假设将t: => Long改成t: Long。则依照值传递进行计算。结果例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" style="border:none; max-width:100%">

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

还有一个演示样例代码例如以下:

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

假设将msg: =>String改为msg: String。则运行代码就会报错

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

使用“按名称传递參数”方式的长处是:1.降低不必要的计算。 2.降低异常

在正常的函数调用中。调用參数在调用函数中是按其定义时的參数顺序进行一一匹配。

假设须要按不同的顺序传递參数。就要使用到scala的一种函数特性——命名參数。

命名參数用法非常easy,即在调用函数时,指定參数名并进行赋值。演示样例代码例如以下:

结果:

从代码和结果中就能够看出使用命名參数的长处:在须要时能够随意的指定函数中某个參数的值,而不必将此參数之前的參数都赋值一遍。

scala同java一样。在定义函数的时候支持接收可变长參数列表。即最后一个參数的能够被反复。

演示样例代码例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="440" height="260" alt="" style="border:none; max-width:100%">

结果:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="86" height="100" alt="" style="border:none; max-width:100%">

在此代码中我们定义函数printInfo接收变长參数列表。其最后一个參数names能够依据实际情况进行传參(这里我们传了3个实參)。

注意。函数可变參数仅仅能是该函数的最后一个參数(否则不能识别參数长度,这个应该非常好理解)。

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

在scala中,函数是“头等公民”,差点儿全部的操作都是以函数形式进行。相同的,可以在变量中存放函数(听上去非常奇妙吧)。示比例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="300" height="140" alt="" style="border:none; max-width:100%">

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

在scala中。不须要为每一个函数命名,这样的没有命名的函数叫做匿名函数

怎样进行匿名函数的定义呢?示比例如以下:

(x:Double) => 3 * x

这就是一个匿名函数。

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

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

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

deftriple(x: Double) = 3 * x

可是优点就是可以不给函数命名,就能直接将它传递给还有一个函数。这样的方法在使用map、filter等函数时很经常使用:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="610" height="101" alt="" style="border:none; max-width:100%">

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

在此代码中,我们将BufferedWriter进行了封装。仅仅要调用autoWrite函数,传入适当的參数,就能够完毕字符串写入文件,并且不须要关闭BufferedWriter。

使用借贷模式是对系统资源操作的封装,为了防止资源不被安全释放。其次用户不用考虑资源来自何处,怎样归还等问题,仅仅须要使用即可了。


带函数參数的函数因为是一个接受函数參数的函数,故被称为高阶函数。像之前讲到的map()函数就是高阶函数。例如以下例所看到的:

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

相同的。高阶函数也能够产出还有一个函数(即返回结果为一个函数,而不是某个值或对象)。例如以下例所看到的:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="603" height="132" alt="" style="border:none; max-width:100%">

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

在高阶函数中,常常将仅仅须要运行一次的函数定义为匿名函数作为參数传递给高阶函数。就好像map()、filter()等高阶函数中常常能看到使用了匿名函数作为參数。匿名函数在这里有一个特性可以帮助我们写出更easy阅读的函数——參数判断

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

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="406" height="126" alt="" style="border:none; max-width:100%">

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

而且假设匿名函数仅仅有一个參数。则能够省略()。继续简化:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="320" height="124" alt="" style="border:none; max-width:100%">

在此基础上,假设參数在=>右边仅仅出现了一次。则能够用_替换它:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="323" height="124" alt="" style="border:none; max-width:100%">

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

结果:

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

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

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

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="602" height="164" alt="" style="border:none; max-width:100%">

使用柯里化后,该函数柯里化后单独对第二个參数进行了更具体的功能定义。丰富了函数的功能

Scala函数特性的更多相关文章

  1. [Scala函数特性系列]——按名称传递参数

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

  2. 02.Scala高级特性:第6节 高阶函数;第7节 隐式转换和隐式参数

    Scala高级特性 1.    课程目标 1.1.   目标一:深入理解高阶函数 1.2.   目标二:深入理解隐式转换 2.    高阶函数 2.1.   概念 Scala混合了面向对象和函数式的特 ...

  3. scala 语言特性

    Scala 语言特性 Unit 表示无值, 等价于java, C++中的void Null 表示空值或空引用 Nothing 所有其他类型的子类型, 表示没有值 Any 所有类型的超类, 任何实例都属 ...

  4. Scala 函数(五)

    函数是一组一起执行一个任务的语句. 您可以把代码划分到不同的函数中.如何划分代码到不同的函数中是由您来决定的,但在逻辑上,划分通常是根据每个函数执行一个特定的任务来进行的. Scala 有函数和方法, ...

  5. Scala:函数和闭包

    http://blog.csdn.net/pipisorry/article/details/52902271 Scala函数 Scala 有函数和方法,二者在语义上的区别很小.Scala 方法是类的 ...

  6. Scala进阶之路-Scala函数篇详解

    Scala进阶之路-Scala函数篇详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.传值调用和传名调用 /* @author :yinzhengjie Blog:http: ...

  7. Spark记录-Scala函数

    Scala函数 Scala有函数和方法. Scala方法是一个具有名称和签名的类的一部分. Scala中的函数是一个可以分配给变量的完整对象. 函数定义可以出现在源文件中的任何位置. 不带参数的函数 ...

  8. Spark记录-Scala函数与闭包

    函数声明 Scala函数声明具有以下形式 - def functionName ([list of parameters]) : [return type] Scala 如果不使用等号和方法体,则隐式 ...

  9. [scala] scala 函数 (⑦)

    1.scala 函数定义 2.scala 高阶函数 3.匿名函数 4.柯里化 import scala.math._ /** * @author xwolf * @date 2017-04-24 9: ...

随机推荐

  1. java POi excel 写入大批量数据

    直接贴代码: package jp.co.misumi.mdm.batch.common.jobrunner; import java.io.File; import java.io.FileNotF ...

  2. C语言 · 利息计算

    算法提高 利息计算   时间限制:1.0s   内存限制:512.0MB      编制程序完成下述任务:接受两个数,一个为用户一年期定期存款金额,一个为按照百分比格式表示的利率:程序计算一年期满 后 ...

  3. 扩展RBAC用户角色权限设计方案<转>

    RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联.简单地说,一个用户拥有若干角色,每一个角色拥有若干权限.这样,就构造成“用户-角色- ...

  4. centos7 /etc/rc.local需要chmod +x /etc/rc.d/rc.local

    Centos 7.0设置/etc/rc.local无效问题解决 安装centos7以后按照以往习惯修改rc.local添加开机启动命令,但重启后发现无效,再次重启发现依然如故 检查系统rc.local ...

  5. list中存放map实例

    list中存放map实例 2016年08月08日 18:46:14 阅读数:22279 List中存放Map遍历输出的实例   import java.util.ArrayList;   import ...

  6. 程序中判断android系统版本

    public static int getAndroidSDKVersion() { int version; try { version = Integer.valueOf(android.os.B ...

  7. JavaScript的gzip静态压缩方法记录

    传统的JS压缩(删除注释,删除多余空格等)提供的压缩率有时还是不尽不意,幸亏现在的浏览器都支持压缩传输(通过设置http header的Content-Encoding=gzip),可以通过服务器的配 ...

  8. 数据库 proc编程四

    错误处理机制 当在Pro*C/C++应用程序中运行SQL语句中,Oracle会将最近执行的SQL语句的状态信息存储到状态变量SQLCODE.SQLSTATE或者SQLCA结构中. 当SQL语句执行成功 ...

  9. php -- PHP5中file_get_contents函数获取带BOM的utf-8文件内容

    最近,在用file_get_contents函数来取得文本的内容的时候,出现了一个情况(如下),苦思冥想了n久,不得其解,最后,果然还是得靠百度啊..... 百度到一个解释,下面是原文: PHP5中的 ...

  10. Mysql命令行添加用户并且给予远程访问服务器的权限

    --查询用户SELECT User, Password, Host FROM user; --创建一个用户,任意主机可以登录%,密码是123456 '; -- 给用户赋予所有权限 GRANT ALL ...