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 - 函数值的更多相关文章

  1. scala学习手记28 - Execute Around模式

    我们访问资源需要关注对资源的锁定.对资源的申请和释放,还有考虑可能遇到的各种异常.这些事项本身与代码的逻辑操作无关,但我们不能遗漏.也就是说进入方法时获取资源,退出方法时释放资源.这种处理就进入了Ex ...

  2. scala学习手记26 - 重用函数值

    函数值对消除代码重复有很大的帮助.但是像函数值这样直接将一个函数作为另一个函数的参数却不太利于函数值本身的重用. 来看一个例子: class Equipment(val routine: Int =& ...

  3. scala学习手记24 - 多参数函数值

    上一节的函数值只有一个参数.函数值当然也是可以有多个参数的.看一下下面的inject方法: def inject(arr: Array[Int], initial: Int, operation: ( ...

  4. scala学习手记38 - 方法命名约定和for表达式

    方法命名约定 之前在学习<运算符重载>一节时曾经说过一个方法命名约定:方法的第一个字符决定了方法的优先级.现在再说另一个命名约定:如果方法以冒号(:)结尾,则调用目标是运算符后面的实例. ...

  5. scala学习手记39 - 模式匹配

    在java中有switch/case这样的模式匹配语句,可以匹配的类型包括int,byte,char,short, enum,在java8又支持了字符串. 在scala中也有类似的模式匹配语句,即ma ...

  6. scala学习手记37 - 容器的使用

    这次统一看一下scala中容器类的几个方法. Set filter()方法 filter()方法用来从Set中过滤获取含有指定特征的元素.示例代码如下: val colors1 = Set(" ...

  7. scala学习手记30 - 闭包

    首先要弄白闭包的概念. 教材中的说法是:闭包是一种特殊的函数值,闭包中封闭或绑定了在另一个作用域或上下文中定义的变量.这里说闭包是一种特殊的函数值. 维基百科中的说法是:在计算机科学中,闭包(英语:C ...

  8. scala学习手记27 - 下划线与参数

    在Scala里,下划线(_)可以表示函数值的参数.如果某个参数在函数里仅使用一次,就可以用下划线表示.每次在函数里用下划线,都表示随后的参数. val arr = Array(1, 2, 3, 4, ...

  9. scala学习手记17 - 容器和类型推断

    关于scala的类型推断前面已经提到过多次.再来看一下下面这个例子: import java.util._ var list1: List[Int] = new ArrayList[Int] var ...

随机推荐

  1. 160629、 DBCP、C3P0、Proxool 、 BoneCP开源连接池的比较

       简介   使用评价  项目主页  DBCP DBCP是一个依赖Jakarta commons-pool对象池机制的数据库连接池.DBCP可以直接的在应用程序用使用 可以设置最大和最小连接,连接等 ...

  2. Less-loops循环

    loop循环 example: .test(@i) when (@i > 0) { .test((@i - 1)); .study@{i} { width: (10px * @i); } } d ...

  3. 通过创建脚本代替"scrapy crawl Test"命令

    文件结构: 1.在命令行scrapy crawl Test正常运行的条件下在项目的根目录创建start.py文件(注意目录,同scrapy.cfg文件一个目录): start.py源代码: # -*- ...

  4. ChannelOption用到的socket的标准参数

    ChannelOption.SO_BACKLOG, 1024 BACKLOG用于构造服务端套接字ServerSocket对象,标识当服务器请求处理线程全满时,用于临时存放已完成三次握手的请求的队列的最 ...

  5. 无NavigationBar到有NavigationBar视图切换时的一个坑

    NavigationController在iOS App中是最常见不过了,可以说是每个App中必备的了.自iOS7开始,系统自带的右滑返回效果,也可以让有NavigationBar的视图切换很丝滑流畅 ...

  6. tpot从elastic search拉攻击数据之三 用于拉取的java程序

    package download; import org.json.JSONArray; import java.io.*; import java.net.URL; import java.net. ...

  7. linux c编程:Posix信号量

    POSIX信号量接口,意在解决XSI信号量接口的几个不足之处: POSIX信号量接口相比于XSI信号量接口,允许更高性能的实现. POSIX信号量接口简单易用:没有信号量集,其中一些接口模仿了我们熟悉 ...

  8. 蛇形命名法(snake case)驼峰命名法(camel case)字符转换问题

    描述小 Hi 写程序时习惯用蛇形命名法(snake case)为变量起名字,即用下划线将单词连接起来,例如:file_name. line_number.小 Ho 写程序时习惯用驼峰命名法(camel ...

  9. 采购订单打印并预览PDF

    *&---------------------------------------------------------------------* *& Report Z01MMF019 ...

  10. 前端基础之JavaScript(Day53)

    阅读目录 一.JavaScript基础 二.JavaScript对象 三.BOM对象 一.JavaScript基础 http://www.cnblogs.com/yuanchenqi/articles ...