Scala编程(第4版)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

7.8 对指令式代码进行重构

为了帮助你对函数式编程有更深的领悟,本节将对示例7.18的指令式风格打印乘法表的做法进行重构。我们的函数式版本如示例7.19所示。

示例7.19 用函数式编程的方式创建乘法表

示例7.18中的指令式风格体现在两个方面。首先,调用printMultiTable有一个副作用:将乘法表打印到标准输出。在示例7.19中,我们对函数进行了重构,以字符串的形式返回乘法表。由于新的函数不再执行打印,我们将它重命名为multiTable。就像我们先前提到的,没有副作用的函数的优点之一,是它们更容易进行单元测试。要测试printMultiTable,需要以某种方式重新定义printprintln,这样你才能检查输出是否正确。而测试multiTable则更容易,只要检查它的字符串返回值即可。

其次,printMultiTable用到了while循环和var,这也是指令式风格的体现。相反地,函数multiTable用的是valfor表达式、助手函数helper function)和对mkString的调用。

我们重构出两个助手函数makeRowmakeRowSeq,让代码更易读。函数makeRowSeq使用for表达式,其生成器遍历列号1到10。这个for表达式的执行体计算行号和列号的乘积,确定乘积需要的对其补位,并交出将补位符和乘积拼接在一起的字符串结果。for表达式的结果将会是一个包含以这些交出的字符串作为元素的序列(scala.Seq的某个子类)。而另一个助手函数makeRow只是简单地对makeRowSeq调用mkStringmkString会把序列中的字符串拼接起来,返回整个字符串。

multiTable方法首先用一个for表达式的结果初始化tableSeq。这个for表达式的生成器会遍历1到10,对每个数调用makeRow得到对应行的字符串;这个字符串被交出,因此这个for表达式的结果将会是包含了一行对应的字符串的序列。接下来就是将这个字符串序列转换成单个字符串了,调用mkString可以做到这一点。由于我们传入了"\n",所以在每两个字符串中间都插入了一个换行符。如果将multiTable返回的字符串传给println,将会看到跟调用printMultiTable相同的输出。