繼續領悟函數式:Scala指令式風格代碼的重構
為了幫助你在函數式風格上獲得更多的領悟,本節我們將重構代碼7.18中以指令式風格打印乘法表的方式。我們的函數式替代品展示在代碼7.19中。
51CTO編輯推薦:Scala編程語言專題
代碼7.18中的代碼在兩個方面顯示出了指令式風格。首先,調用printMultiTable有副作用:在標準輸出上打印乘法表。代碼7.19中,我們重構了函數,讓它把乘法表作為字串返回。由于函數不再執行打印,我們把它重命名為multiTable。正如前面提到過的,沒有副作用的函數的一個優點是它們很容易進行單元測試。要測試printMultiTable,你需要重定義print和println從而能夠檢查輸出的正確性。測試multiTable就簡單多了,只要檢查結果即可。
代碼 7.19 創建乘法表的函數式方法
- // 以序列形式返回一行乘法表
- 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")
- }
printMultiTable里另一個揭露其指令式風格的信號來自于它的while循環和var。與之相對,multiTable函數使用了val,for表達式,幫助函數:helper function,并調用了mkString。
我們提煉出兩個幫助函數,makeRow和makeRowSeq,使代碼容易閱讀。函數makeRowSeq使用for表達式從1到10枚舉列數。這個for函數體計算行和列的乘積,決定乘積前占位的空格,并生成由占位空格,乘積字串疊加成的結果。for表達式的結果是一個包含了這些生成字串作為元素的序列(scala.Seq的某個子類)。另一個幫助函數,makeRow,僅僅調用了makeRowSeq返回結果的mkString函數。疊加序列中的字串把它們作為一個字串返回。
multiTable方法首先使用一個for表達式的結果初始化tableSeq,這個for表達式從1到10枚舉行數,對每行調用makeRow獲得該行的字串。因為字串前綴yield關鍵字,所以表達式的結果就是行字串的序列。現在僅剩下的工作就是把字串序列轉變為單一字串。mkString的調用完成這個工作,并且由于我們傳遞進去"\n",因此每個字串結尾插入了換行符。如果把multiTable返回的字串傳遞給println,你將看到與調用printMultiTable所生成的同樣的輸出結果。
【相關閱讀】