scala学习手记23 - 函数值
scala的一个最主要的特性就是支持函数编程。函数是函数编程中的一等公民:函数可以作为参数传递给其他函数,可以作为其他函数的返回值,甚至可以在其它函数中嵌套。这些高阶函数称为函数值。
举一个简单的例子:从1到某个数求和。使用Java很容易实现:
int sum(int max){
int result = 0;
for (int i = 0; i <= max; i++) {
result +=i;
}
return result;
}
使用scala实现也没有多大区别。
现在再扩展下需求:对某个范围内的奇数或偶数求和。使用java该怎么办呢,最直接的方式分别为奇数和偶数求和写一套方案就行了。但是这样纯粹重复的体力工作好像有些招人烦。此时如果能把奇偶分析的逻辑作为参数传递进来肯定是极好的。看看是如何使用函数式的方案来进行实现的:
def totalOverRange(max: Int, func: Int => Int): Int = {
var result = 0;
for (i <- 1 to max) {
result += func(i)
}
result
}
这里定义了一个totalOverRange函数来进行计算,这个函数有两个参数max和func。其中max是一个普通参数,表示循环的最大值。func则是一个函数值,其本质上是一个函数,接收一个Int并返回一个Int。在totalOverRange的方法体里,循环值的逻辑处理交由函数值func来实现,totalOverRange只负责累计。
先来试一下从1到max的简单求和:
print(totalOverRange(5, i=>i))
上面的代码段在调用totalOverRange方法时传递了两个参数,第一个参数标识循环到5,第二个参数“i=>i”则是一个匿名函数(也就是只有实现没有名字的函数),用来表示对循环值的处理逻辑。在函数中使用“=>”将左侧的参数列表和函数实现分开。这里的函数实现只是简单地将参数i返回。需要注意的是这里不需要指定函数值参数的类型,scala会从totalOverRange方法中推断出参数的类型。看一下执行结果:
再来做一下对5以内的偶数求和:
print(totalOverRange(5, i => if (i % 2 == 0) i else 0))
一开始我是这样写函数值的:
i => if (i % 2 == 0) return i else return 0
添加了return,但是这样做是错误的。不明白为什么,希望稍后的学习中可以解惑。
看一下执行结果:
奇数运算的逻辑就不需要我写了。
使用函数值的一个好处在这里已经显示出来了:可以减少代码的重复。将公共代码放到一个函数里,将差异的部分封装为函数值参数传递进去,从而减少代码的重复。这样子看起来是有些类似于模板方法模式的,不过不需要定义那么多的接口和类而已。
再想一下,如果作为函数值的函数很复杂该怎么办呢?是使用函数方案还是模板模式方案?
我也不好说,具体情况再具体分析吧。
#######
scala学习手记23 - 函数值的更多相关文章
- scala学习手记28 - Execute Around模式
我们访问资源需要关注对资源的锁定.对资源的申请和释放,还有考虑可能遇到的各种异常.这些事项本身与代码的逻辑操作无关,但我们不能遗漏.也就是说进入方法时获取资源,退出方法时释放资源.这种处理就进入了Ex ...
- scala学习手记26 - 重用函数值
函数值对消除代码重复有很大的帮助.但是像函数值这样直接将一个函数作为另一个函数的参数却不太利于函数值本身的重用. 来看一个例子: class Equipment(val routine: Int =& ...
- scala学习手记24 - 多参数函数值
上一节的函数值只有一个参数.函数值当然也是可以有多个参数的.看一下下面的inject方法: def inject(arr: Array[Int], initial: Int, operation: ( ...
- scala学习手记38 - 方法命名约定和for表达式
方法命名约定 之前在学习<运算符重载>一节时曾经说过一个方法命名约定:方法的第一个字符决定了方法的优先级.现在再说另一个命名约定:如果方法以冒号(:)结尾,则调用目标是运算符后面的实例. ...
- scala学习手记39 - 模式匹配
在java中有switch/case这样的模式匹配语句,可以匹配的类型包括int,byte,char,short, enum,在java8又支持了字符串. 在scala中也有类似的模式匹配语句,即ma ...
- scala学习手记37 - 容器的使用
这次统一看一下scala中容器类的几个方法. Set filter()方法 filter()方法用来从Set中过滤获取含有指定特征的元素.示例代码如下: val colors1 = Set(" ...
- scala学习手记30 - 闭包
首先要弄白闭包的概念. 教材中的说法是:闭包是一种特殊的函数值,闭包中封闭或绑定了在另一个作用域或上下文中定义的变量.这里说闭包是一种特殊的函数值. 维基百科中的说法是:在计算机科学中,闭包(英语:C ...
- scala学习手记27 - 下划线与参数
在Scala里,下划线(_)可以表示函数值的参数.如果某个参数在函数里仅使用一次,就可以用下划线表示.每次在函数里用下划线,都表示随后的参数. val arr = Array(1, 2, 3, 4, ...
- scala学习手记17 - 容器和类型推断
关于scala的类型推断前面已经提到过多次.再来看一下下面这个例子: import java.util._ var list1: List[Int] = new ArrayList[Int] var ...
随机推荐
- [cocos2dx] cocosdx编译工程那些事
cocos compile -p android 上面这条命令可以将cocos2dx的工程编译出android apk,需要注意的是如果有新增的cpp文件,都需要在“CocosProject\proj ...
- <td></td>之间的
今天开发中遇到了一个很丢脸的事:我把下图中别人写的 给去掉了,我觉得这个很多余,结果被在大神们痛斥了一顿.因为去掉这个 会导致td之间没有数据时td的边框不显示的问题,所以几下这个惨痛的教训,以自警. ...
- json.dumps 和 json.dump的区别,load和loads的区别
json.dumps 和 json.dump的区别,load和loads的区别
- Java 之包
作用: 对类文件进行分类管理, 类似于文件夹 给类提供多层命名(名称)空间 写在程序的第一行, 包名使用小写 类名的全称是: 包名.类名 包也是一种封装形式 // 示例 package mypack; ...
- win7下docker配置加速器
1.docker-machine ssh default(有时可省略) 2.sudo sed -i "s|EXTRA_ARGS='|EXTRA_ARGS='--registry-mirror ...
- git学习------>如何用git log命令来查看某个指定文件的提交历史记录
有时候接手一份新代码时,看到某些文件的改动,但不清楚这个改动的作者和原因,想查看该文件的具体提交历史记录. 今天一个同事是这样做的,直接敲git log命令,然后再使用vim命令的搜索关键字的方法来查 ...
- 解读tensorflow之rnn 的示例 ptb_word_lm.py
这两天想搞清楚用tensorflow来实现rnn/lstm如何做,但是google了半天,发现tf在rnn方面的实现代码或者教程都太少了,仅有的几个教程讲的又过于简单.没办法,只能亲自动手一步步研究官 ...
- tomcat 6 利用ExpiresFilter控制静态文件缓存
在tomcat7下面 利用ExpiresFilter来控制静态文件缓存很方便,按照tomcat官网手动配置即可: 但是tomcat6 里面并没有 org.apache.catalina.filters ...
- matlab出错及改正
1 使用小波分析时,出现下面错误: 错误使用 wavedec需要的 X 应为 矢量.出错 wavedec (line 34)validateattributes(x,{'numeric'},{'vec ...
- C/C++中的输出对齐设置
输出对齐有两个方面,一是输出宽度,一是左对齐还是又对齐. 在C++里面,默认是右对齐,可以通过cout.setf(std::ios::left)调整为左对齐,而且这种调整是全局的 ,一次设置,后面都有 ...