首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Scala如何改变了我的编程风格:从命令式到函数式

Scala如何改变了我的编程风格:从命令式到函数式

作者头像
Albert陈凯
发布2018-04-04 15:02:24
1K0
发布2018-04-04 15:02:24
举报
文章被收录于专栏:Albert陈凯Albert陈凯

51CTO编辑推荐: Scala编程语言专题

【51CTO快译】编者前言:这篇文章最初写于2008年底,作者Bill Venners一方面是美国著名开发网站Artima的总编,另一方面也是一位十分关注Scala语言的Java程序员。在这几个月间的Scala创始人Martin Odersky访谈系列中,与Martin对话的正是Bill Venners。这篇文章虽然已经完成了半年有余,但对于还不很熟悉Scala语言的Java程序员而言,仍然是一篇非常实用的Scala语言简介。以下是译文:

每次我学习一门新的语言,我都会学到某些编程方面的东西。比如说,当我以一个C++程序员的身份学习Java的时候,Java的接口构造教会我来自纯粹的抽象基类的多重继承的价值。尽管在C++里面这种编程风格是有可能的,但在我使用C++的日子里,我却没有考虑用这种方式进行多重继承,而我在C++设计中也不怎么使用抽象基类。然而,一旦我开始进行Java编程,我就开始一直使用这种风格了。学习Java—尤其是它的接口构造—改变了我OO设计的方法。

51CTO编辑推荐: 充分利用面向对象语言的接口特性 | 面向对象的思维过程

我学习 Scala编程的时候也发生了类似的情况。在过去的两年里,我有相当多的时间是用 Scala工作的,Scala是Java平台上的一种新的静态类型语言,它融合了面向对象编程和函数型程序设计的概念。Scala能让我写出几乎跟Ruby和Python 一样简洁的代码。在 Scala 我可以跟在 Java 里面一样方便地调用 Java 库,包括我已有的 Java 库。考虑到 Scala 是静态类型的,我可以享受到诸多静态类型的好处,诸如将文档作为类型, IDE 代码自动完成,动态代码重构( deterministic refactoring )以及执行速度等( Scala 程序的执行速度跟 Java 的一样快)。但 Scala 还让我以简洁和类型安全的方式获得某些通常是动态语言的好处,例如在已有类上增加新方法的能力,或者将类型传递给没有共同继承关系的方法。

Scala 是怎样改变了我对编程的看法的呢?一句话:我学会了欣赏函数化的风格。函数化的编程风格强调不可变对象、变量可被初始化但不能重新赋值( Java 中的最终变量)、数据结构转换,以及方法和控制的构造,最终产生一个没有副作用的结果。这个领域的另一端是命令式的风格,以可变对象、变量可被重新赋值( Java 里的正常变量)、在数据结构中索引、以及带副作用的方法和控制构造为特征。

尽管 Scala 经常被吹捧为函数型编程语言,当它并不仅仅是函数型的。 Scala 同时支持函数式和命令式两种风格。如果你自己选择要这么做的话,你可以以 Java 的编程方式进行 Scala 编程,那种风格主要是命令式的。这样有助于 Scala 的学习曲线变缓,但随着对 Scala 越来越熟悉,你就会发现自己会更喜欢函数式的。我就是这样。为什么?因为我发现函数型风格往往要比命令式风格的代码更简洁,且更不易出错。函数式风格的代码通常层次更高,这使得它编写起来更快,阅读也更为容易。举个例子,看看下面这段确定一个字符串是否包含大写字符的 Java 代码。

boolean nameHasUpperCase = false; // 这是Java
for (int i = 0; i < name.length(); ++i) {

    if (Character.isUpperCase(name.charAt(i))) {

        nameHasUpperCase = true;

        break;

    } 

}

这里的命令式风格是很明显的,因为 nameHasUpperCase 变量被重新赋值会给 loop 循环带来副作用, loop 是通过字符串中的字母索引进行迭代的。在 Java 你还可以以更为简洁的方式得到相同的结果,像下面这样:

boolean nameHasUpperCase = !name.toLowerCase().equals(name);

这一行 Java 代码展现出一种更为函数化的风格,因为它转换不可变数据: name 这个字符串被转换为另外一个全部字母都是小写的字符串,然后值被转换为布尔结果。此外, nameHasUpperCase 这个变量被初始化了,但仅限于这一小块代码里,而没有被重新赋值。如果该变量为最终值的话,它的函数化就会更为清晰。

在 Scala 里面,你可以写出跟以上两个例子类似的代码,不过更为理想的编写方式是像下面这样的:

val nameHasUpperCase = name.exists(_.isUpperCase)

nameHasUpperCase 变量被定义为 val ,即可被初始化但不能被重新赋值的变量(类似于 Java 里面的最终变量)。甚至于尽管本例中并无显式的类型标注, Scala 的类型推断机制也会给 nameHasUpperCase 赋予 Boolean 类型。 exists 方法在对象集合中迭代,并依次将每个元素传递给函数对象。在这里, name 字符串被视为字符集合,因此 exists 会把字符串的每一个字符都传递给该函数。 _.isUpperCase 的语法是 Scala 里的一种函数显式声明( function literal ),是一种编写少量代码就可以到处传递和调用的速写方式。下划线代表该函数的唯一参数。因此你可以把下划线视为每次该函数被调用时待填的空白。如果 exists 方法发现该函数因被传递的字符中的其中一个而返回 true— 比如说,其中一个字符是大写的 — 而返回 true 。否则就返回 false 。

尽管最后的这个单行代码对于某些不熟悉Scala的人来说像是天书,只要你了解了 Scala,你就能一眼看出代码的目的。相反,其他的两个版本却要费上一点功夫去研究一下。另外需要注意的一点不同是命令式例子中潜在的偏移错误,因为你必须显式地指出迭代的上标。在函数化的版本里这种错误不会产生,在这种方式下,函数化版本相对而言不易出错。

最后,我想指出的是我转向 Scala 的时候并没有“彻底函数化”。尽管我已经发现通常大部分情况下函数化风格的代码来得更为简洁、明晰,更不易出错,我还发现有时候命令式风格也可带来更为清晰和简洁的代码。在那种情况下,我就会使用命令式的。 Scala 允许我方便地应用函数式和命令式的风格,结合使用此二者,我就能找到写出清晰代码的最佳方式。

函数式编程和命令式编程简介

什么是函数式编程?(参考资料:《征服RIA:基于JavaScript的Web客户端开发》第8章JavaScript函数对象 在数学领域,函数是一种关系,这种关系使一个集合里的每一个元素对应到另一个集合里的唯一元素。函数是将唯一的输出值赋予每一输入的"法则"。这一"法则"可以用函数表达式、数学关系,或者一个将输入值与输出值对应列出的简单表格来表示。函数最重要的性质是其决定性,即同一输入总是对应同一输出(注意,反之未必成立)。从这种视角,可以将函数看做"机器"或者"黑盒",它将有效的输入值变换为唯一的输出值。通常将输入值称做函数的参数,将输出值称做函数的值。 《Why Functional Programming Matters》的作者John Hughes 说明了模块化是成功编程的关键,而函数编程可以极大地改进模块化。在函数编程中,编程人员有一个天然框架用来开发更精练的、更小的、更简单的和更一般化的模块,然后将它们组合在一起。函数式编程的基本特点是: 丰富的数据类型; 函数是运算元; 在函数内保存数据; 函数内的运算对函数外无副作用。 函数式编程只描述在程序输入上执行的操作,不必使用临时变量保存中间结果。重点是捕捉"是什么以及为什么",而不是"如何做"。与将重点放在执行连续命令上的过程性编程相比,函数式编程的重点是函数的定义而不是状态机(State Machine)的实现。是一种强调表达式的计算而非命令的执行的一种编程风格。表达式是用函数结合基本值构成的,它类似于用参数调用函数(函数式的优美的说明可见《Functional Programming For The Rest of Us》)。 什么是命令式编程?(参考资料:维基百科) 命令式编程,是种描述电脑所需作出的行为的编程典范。几乎所有电脑的硬体工作都是命令式的;几乎所有电脑的硬体都是设计来执行机器码,使用命令式的风格来写的。较高阶的命令式编程语言使用变数和更复杂的语句,但仍依从相同的典范。食谱和行动清单,虽非电脑程式,但与命令式编程有相似的风格:每步都是指令,有形的世界控制情况。因为命令式编程的基础观念,不但概念上比较熟悉,而且较容易具体表现于硬体,所以大部分的编程语言都是命令式的。 原文:How Scala Changed My Programming Style 作者:Bill Venners

【相关阅读】 Scala的类型系统 比Java更灵活 Java程序员,你为什么要关注Scala Scala创始人:创造比Java更好的语言 Java以外的选择 Scala编程语言简介 Java之外,选择Scala还是Groovy?

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.05.23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档