Scala學習:簡化客戶代碼
9.2 前一個例子演示了高階函數能在你實現API的時候幫助減少代碼重復。高階函數的另一個重要應用是把它們放在API里使客戶代碼更簡潔。Scala的集合類型的特定用途循環方法提供了一個很好的例子。這些特定用途循環方法被定義在特質Iterable中,被List,Set,Array,還有Map擴展。很多已經在第三章的表格3.1中列了出來。不過現在請注意其中的一個例子來看看為什么這些方法如此有用。
51CTO編輯推薦:Scala編程語言專題
考慮exists,一個判斷傳入的值是否包含在集合中的方法。當然你也可以初始化一個var為假,循環遍歷集合類型,檢查每個元素,并且如果你找到了要尋找的就把var設置為真,通過這樣的方式尋找元素。以下是使用了這種方式的方法去判斷是否傳入的List包含了負數的例子:
假如你在解釋器里定義了這個方法,你就可以這樣調用:
- def containsNeg(nums: List[Int]): Boolean = {
- var exists = false
- for (num < - nums)
- if (num < 0)
- exists = true
- exists
- }
不過更簡潔的定義這個方法的方式是通過在傳入的List上調用高階函數exists,如:
- scala> containsNeg(List(1, 2, 3, 4))
- res0: Boolean = false
- scala> containsNeg(List(1, 2, 3, -4))
- res1: Boolean = true
這個版本的containsNeg能產生和前面的那個一樣的結果:
- def containsNeg(nums: List[Int]) = nums.exists(_ < 0)
exists方法代表了控制抽象。是Scala庫提供的特定用途循環架構而不是像while或for那樣內建在Scala語言里的。上節中,高階函數,filesMatching在對象FileMatcher的實現中減少了代碼重復。exists方法提供了類似的好處,但因為exists是公開在Scala的集合類型API里的,所以它減少的是API的客戶代碼中的重復。exists不存在的話,如果你想要寫一個containsOdd方法,檢測列表是否包含了奇數,你或許會寫成這樣:
- scala> containsNeg(Nil)
- res2: Boolean = false
- scala> containsNeg(List(0, 1, -2))
- res3: Boolean = true
若你比較了containsNeg和containsOdd的函數體,你會發現除了if表達式之外,其它東西都是重復的。使用exists,你就可以這么寫:
- def containsOdd(nums: List[Int]): Boolean = {
- var exists = false
- for (num < - nums)
- if (num % 2 == 1)
- exists = true
- exists
- }
這個版本的代碼體再一次與相應的containsNeg方法的保持一致(使用了exists的版本),除了搜索的條件不同。然而代碼重復的量卻少得多,因為所有的循環架構都被提取成exists方法本身了。
- def containsOdd(nums: List[Int]) = nums.exists(_ % 2 == 1)
Scala的標準庫中還有許多其他循環方法。如果你能發現使用它們的機會,那么像exists一樣,它們經常能縮短你的代碼。
【相關閱讀】