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. 160812、apache milagro分布式安全认证系统

    java32位.64位及js的代码:http://pan.baidu.com/s/1cqnwuE 一.云链接为中心的软件及需要互联网规模物联网设备 二.利用双线性密码学分发加密操作和分裂的加密参数 三 ...

  2. Linux下修改Mysql的用(root的密码及修改root登录权限

    修改的用户都以root为列. 一.知道原来的myql数据库的root密码: ①: 在终端命令行输入 mysqladmin -u root -p password "新密码" 回车  ...

  3. Powershell Function Get-TimeZone

    代码原文地址: https://gallery.technet.microsoft.com/scriptcenter/Get-TimeZone-PowerShell-4f1a34e6 <# .S ...

  4. c++用vector创建二维数组

    1 vector二维数组的创建和初始化 std::vector <int> vec(10,90); //将10个一维动态数组初始为90std::vector<std::vector& ...

  5. link options and how g++ is invoked gcc g++

    yum install gcc yum install gcc-c++ yum reinstall gcc gcc-c++ Downloading packages:(1/2): gcc-c++-4. ...

  6. python基础之类的继承与派生、组合、接口与归一化设计、抽象类、子类中调用父类方法

    一.什么是继承 继承是一种创建新的类的方式,新建的类可以继承自一个或者多个父类,原始类称为基类或超类,新建的类称为派生类或子类. 派生:子类继承了父类的属性,然后衍生出自己新的属性,如果子类衍生出的新 ...

  7. MongoDB-5: 查询(游标操作、游标信息)

    一.简介 db.collection.find()可以实现根据条件查询和指定使用投影运算符返回的字段省略此参数返回匹配文档中的所有字段.并返回到匹配文档的游标,可以随意修改查询限制.跳跃.和排序顺序的 ...

  8. android应用程序优化之布局优化

    在我们开发APP时不仅要在代码实现上.做到对App的优化,而在我们的界面布局也有很多要优化的地方,假设布局写的非常low的话,系统载入布局的速度会十分的慢,使得用户的体验非常的不好.这篇文章主要是从我 ...

  9. Oracle 11g数据库详解(2)

    FAILED_LOGIN_ATTEMPTS 用于指定连续登陆失败的最大次数 达到最大次数后,用户会被锁定,登陆时提示ORA-28000 UNLIMITED为不限制 精确无误差 是 实时 PASSWOR ...

  10. 生信笔记-mooc【武大】

    .DNA拓扑学 在拓扑结构的限制下,DNA进行复制等过程.还有连环数=扭转数+缠绕数. 2.拓扑异构酶 DNA变性破坏了两条链之间碱基形成的氢键.和拓扑异构酶是不同的. 3.RNA的组成和结构特点 R ...