- Scala編程(第5版)
- (德)馬丁·奧德斯基等
- 1585字
- 2022-05-06 15:51:34
第11步 識別函數式編程風格
正如第1章提到的,Scala允許采用指令式編程風格,但鼓勵采用函數式編程風格。如果你之前的編程背景是指令式的(如果你是一個Java程序員),那么當你學習Scala時的一個主要的挑戰是弄清楚如何使用函數式編程風格。我們意識到這個風格對你來說可能一開始并不熟悉,本書將致力于引導你做出這個轉變。這也需要你自己的努力,我們鼓勵你這樣做。如果你之前更多的是采用指令式編程風格,那么我們相信學習函數式編程風格將幫助你拓寬視野,成為更好的Scala程序員。
首先從代碼層面識別兩種風格的差異。一個顯著的標志是如果代碼包含任何var變量,則它通常是指令式風格的;而如果代碼完全沒有var(也就是說代碼只包含val),則它很可能是函數式的。因此,一個向函數式編程風格轉變的方向是盡可能不用var。
如果你之前用的是指令式的編程語言,如Java、C++或C#,則可能認為var是常規的變量而val是特例;而如果你之前更多地使用函數式的編程語言,如Haskell、OCaml或Erlang,則可能會認為val是常規的變量而var簡直是對編程的褻瀆。在Scala看來,val和var不過是工具箱中的兩種不同的工具,都有相應的用途,沒有哪一個本質上是不好的。Scala更偏向于鼓勵你使用val,但你最終要根據自己手里的工作選擇最適用的工具。然而就算你認同這個平衡的觀點,仍然可能在一開始難以想明白如何從你的代碼中去掉var。
參考如下這個while循環的例子(改編自第2章),由于使用了var,因此它是指令式編程風格的:

可以將這段代碼轉換成更函數式的編程風格,去掉var,就像這樣:

或者這樣:

這個例子展示了編程中使用更少的var的好處。經過重構的(更函數式的)代碼與原始的(更指令式的)代碼相比,更清晰、更精簡,也更少出錯。Scala鼓勵使用函數式編程風格的原因就是這樣能幫助你實現更易讀、更少出現錯誤的代碼。
不過你可以走得更遠。重構后的printArgs方法并不是“純”的函數式代碼,因為它有副作用(本例中它的副作用是向標準輸出流打印)。帶有副作用的函數的標志性特征是結果類型為Unit。如果一個函數并不返回任何有意義的值,也就是Unit這樣的結果類型所表達的意思,那么這個函數存在的唯一意義就是產生某種副作用。一個更函數式的做法是定義一個將傳入的args進行格式化(用于打印)的方法,但只是返回這個格式化的字符串,如示例3.9所示。

示例3.9 一個沒有副作用或var的函數
現在你真的做到了函數式:沒有副作用,也沒有var。mkString方法可以被用于任何可被迭代訪問的集合(包括數組、列表、集和映射),返回一個包含了對所有元素調用toString方法的結果的字符串,并以傳入的字符串分隔。因此,如果args包含3個元素,即"zero"、"one"和"two",則formatArgs將返回"zero\none\ntwo"。當然,這個函數實際上并不像printArgs那樣打印出任何東西,但是可以很容易地將它的結果傳遞給println來達到這個目的:

每個有用的程序都會有某種形式的副作用;否則,它對于外部世界就沒有任何價值。傾向于使用無副作用的函數可以促使你設計出將帶有副作用的代碼最小化的程序。這樣做的好處之一是讓你的程序更容易測試。
例如,要測試本節給出的3個printArgs方法,需要重新定義println,捕獲傳遞給println的輸出,確保它是你預期的樣子。而要測試formatArgs則很簡單,只需要檢查它的結果即可:

Scala的assert方法用于檢查傳入的Boolean,如果傳入的Boolean是false,則拋出AssertionError;如果傳入的Boolean是true,則安靜地返回assert。你將在第25章了解到更多關于斷言(assertion)和測試的內容。
盡管如此,請記住var或副作用從本質上講并非不好。Scala并不是一門純函數式編程語言,強制你只能用函數式風格來編程。Scala是指令式/函數式混合(hybrid)編程語言。你會發現在有些場景下對要解決的問題而言指令式更為適合,這個時候不要猶豫,使用指令式的編程風格就好。為了讓你學習如何不使用var完成編程任務,我們將在第7章向你展示許多具體的用到var的代碼示例,并告訴你如何將這些var轉換成val。
Scala程序員的平衡心態
傾向于使用val、不可變對象和沒有副作用的方法,優先選擇這些方法。不過當你有特定的需要和理由時,也不要拒絕var、可變對象和帶有副作用的方法。
- Practical Data Analysis Cookbook
- Java程序設計與開發
- 國際大學生程序設計競賽中山大學內部選拔真題解(二)
- 高級C/C++編譯技術(典藏版)
- Internet of Things with Intel Galileo
- MySQL數據庫管理與開發(慕課版)
- 網絡爬蟲原理與實踐:基于C#語言
- Mastering Unity 2D Game Development(Second Edition)
- R用戶Python學習指南:數據科學方法
- Rust游戲開發實戰
- Geospatial Development By Example with Python
- INSTANT JQuery Flot Visual Data Analysis
- Laravel Design Patterns and Best Practices
- SQL Server on Linux
- C語言程序設計實驗指導與習題精解