继续领悟函数式:Scala指令式风格代码的重构
为了帮助你在函数式风格上获得更多的领悟,本节我们将重构代码7.18中以指令式风格打印乘法表的方式。我们的函数式替代品展示在代码7.19中。
51CTO编辑推荐:Scala编程语言专题
代码7.18中的代码在两个方面显示出了指令式风格。首先,调用printMultiTable有副作用:在标准输出上打印乘法表。代码7.19中,我们重构了函数,让它把乘法表作为字串返回。由于函数不再执行打印,我们把它重命名为multiTable。正如前面提到过的,没有副作用的函数的一个优点是它们很容易进行单元测试。要测试printMultiTable,你需要重定义print和println从而能够检查输出的正确性。测试multiTable就简单多了,只要检查结果即可。
// 以序列形式返回一行乘法表 def makeRowSeq(row: Int) = for (col < - 1 to 10) yield { val prod = (row * col).toString val padding = " " * (4 - prod.length) padding + prod } // 以字串形式返回一行乘法表 def makeRow(row: Int) = makeRowSeq(row).mkString // 以字串形式返回乘法表,每行记录占一行字串 def multiTable() = { val tableSeq = // 行记录字串的序列 for (row < - 1 to 10) yield makeRow(row) tableSeq.mkString("\n") }代码 7.19 创建乘法表的函数式方法
printMultiTable里另一个揭露其指令式风格的信号来自于它的while循环和var。与之相对,multiTable函数使用了val,for表达式,帮助函数:helper function,并调用了mkString。
我们提炼出两个帮助函数,makeRow和makeRowSeq,使代码容易阅读。函数makeRowSeq使用for表达式从1到10枚举列数。这个for函数体计算行和列的乘积,决定乘积前占位的空格,并生成由占位空格,乘积字串叠加成的结果。for表达式的结果是一个包含了这些生成字串作为元素的序列(scala.Seq的某个子类)。另一个帮助函数,makeRow,仅仅调用了makeRowSeq返回结果的mkString函数。叠加序列中的字串把它们作为一个字串返回。