Scala函数特性
通常情况下,函数的參数是传值參数;即參数的值在它被传递给函数之前被确定。可是,假设我们须要编写一个接收參数不希望立即计算。直到调用函数内的表达式才进行真正的计算的函数。
对于这样的情况。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函数特性的更多相关文章
- [Scala函数特性系列]——按名称传递参数
通常情况下,函数的参数是传值参数:即参数的值在它被传递给函数之前被确定.但是,如果我们需要编写一个接收参数不希望马上计算,直到调用函数内的表达式才进行真正的计算的函数.对于这种情况,Scala提供按名 ...
- 02.Scala高级特性:第6节 高阶函数;第7节 隐式转换和隐式参数
Scala高级特性 1. 课程目标 1.1. 目标一:深入理解高阶函数 1.2. 目标二:深入理解隐式转换 2. 高阶函数 2.1. 概念 Scala混合了面向对象和函数式的特 ...
- scala 语言特性
Scala 语言特性 Unit 表示无值, 等价于java, C++中的void Null 表示空值或空引用 Nothing 所有其他类型的子类型, 表示没有值 Any 所有类型的超类, 任何实例都属 ...
- Scala 函数(五)
函数是一组一起执行一个任务的语句. 您可以把代码划分到不同的函数中.如何划分代码到不同的函数中是由您来决定的,但在逻辑上,划分通常是根据每个函数执行一个特定的任务来进行的. Scala 有函数和方法, ...
- Scala:函数和闭包
http://blog.csdn.net/pipisorry/article/details/52902271 Scala函数 Scala 有函数和方法,二者在语义上的区别很小.Scala 方法是类的 ...
- Scala进阶之路-Scala函数篇详解
Scala进阶之路-Scala函数篇详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.传值调用和传名调用 /* @author :yinzhengjie Blog:http: ...
- Spark记录-Scala函数
Scala函数 Scala有函数和方法. Scala方法是一个具有名称和签名的类的一部分. Scala中的函数是一个可以分配给变量的完整对象. 函数定义可以出现在源文件中的任何位置. 不带参数的函数 ...
- Spark记录-Scala函数与闭包
函数声明 Scala函数声明具有以下形式 - def functionName ([list of parameters]) : [return type] Scala 如果不使用等号和方法体,则隐式 ...
- [scala] scala 函数 (⑦)
1.scala 函数定义 2.scala 高阶函数 3.匿名函数 4.柯里化 import scala.math._ /** * @author xwolf * @date 2017-04-24 9: ...
随机推荐
- hadoop onekey_step2
#onekey_step2 # Rrogram: # 安装hadoop简易集群程序 # 使用说明 # History: # -- luoqi v0. release # email: # @qq.co ...
- 防止js拦截跳转请求的方法
不要直接使用window.open这个方法. 考虑下使用下面这个: openWindow: function(url){ var link = document.createElement('a'); ...
- Spider Studio 新版本 (20140109) - 修复浏览器对部分网页不支持的BUG
SS对部分网页中引用的jquery.js有冲突, 会造成网页部分JS效果无法正常执行. 本次版本对其进行了修正, 优化了浏览器的脚本引用机制, 修正了这个BUG.
- CentOS下yum安装PostgreSQL
关键词:centos install PostgreSQL Configure YUM repository vim /etc/yum.repos.d/CentOS-Base.repo [base] ...
- JQuery EasyUI DataGrid动态合并(标题)单元) 一
JS: /** * EasyUI DataGrid根据字段动态合并单元格 * @param fldList 要合并table的id * @param fldList 要合并的列,用逗号分隔(例如:&q ...
- HBase源码学习系列
转自:http://www.cnblogs.com/cenyuhai/tag/hbase%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/ (mark) hbase源码系列(十 ...
- ubuntu 安装dlib 出现dlib.so: undefined symbol: png_set_longjmp_fn
参考网上的教程安装dlib 安装教程1 sudo apt-get install libboost-python-dev cmake sudo pip install dlib 安装教程2ubuntu ...
- hdu 1253:胜利大逃亡(基础广搜BFS)
胜利大逃亡 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submi ...
- angularJs上传文件(非form上传)
angular.js:13920 Broken interceptor detected: Config object not supplied in rejection: <input typ ...
- POJ 2567 Code the Tree & POJ 2568 Decode the Tree Prufer序列
题目大意:2567是给出一棵树,让你求出它的Prufer序列.2568时给出一个Prufer序列,求出这个树. 思路:首先要知道Prufer序列.对于随意一个无根树,每次去掉一个编号最小的叶子节点,并 ...