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一样,它们经常能缩短你的代码。
【相关阅读】