6.6 参数的位置记法

在Scala里,下划线(_)可以表示函数值的参数。如果某个参数在函数里仅使用一次,就可以用下划线表示。每次在函数里用下划线,都表示随后的参数。先来看个例子:

FunctionValuesAndClosures/Underscore.scala

  1. val arr = Array(1, 2, 3, 4, 5)
  2. println("Sum of all values in array is " +
  3. (0 /: arr) { (sum, elem) => sum + elem }
  4. )

上面的代码里,用/:方法计算数组元素的和。sumelem各只用了一次,就可以省略这些名字,把代码写成这样:

FunctionValuesAndClosures/Underscore.scala

  1. println("Sum of all values in array is " +
  2. (0 /: arr) { _+_}
  3. )

第一个出现的_表示的是一个函数调用过程中持续存在的值,第二个表示数组元素④。或许,你会争辩说,这段代码简短生硬,丧失去了可读性——sumelem这两个名字的存在是有益的。这是个合理的观点。因此,应该在让代码简洁而不失可读性的地方使用_,就像下面这个例子:

④如果Scala无法确定类型,那么它会报错。如果发生了这种情况,可以为_提供类型,或退后一步使用带类型的参数名字。

FunctionValuesAndClosures/Underscore.scala

  1. val negativeNumberExists = arr.exists { _ < 0 }
  2. println("Array has negative number? " + negativeNumberExists)

在某些有意义的地方,这种简洁还可以更进一步。假定有个函数可以得到两个数中的最大值。我们想用这个函数确定数组元素中最大的一个。我们从只在/:()方法中使用它开始:

  1. def max2(a: Int, b: Int) : Int = if (a> b)a else b
  2. var max = (Integer.MIN_VALUE /: arr) { (large, elem) => max2(large, elem) }

我们把一对值(largeelem)传给max2()方法,以确定哪个更大。计算结果最终会用来确定数组中的最大元素。用_简化它可以写成这样:

  1. max = (Integer.MIN_VALUE /: arr) { max2(_, _) }

_不只可以表示一个参数,也可以表示整个参数列表。这样的话,就可以把max2()改成下面这样:

  1. max = (Integer.MIN_VALUE /: arr) { max2 _ }

在上面的代码里,_表示整个参数列表,也就是说,(parameter1, parameter2)。如果只是把接收到的东西传给下层的方法,甚至可以省下使用_的繁文缛节。进一步简化上面的代码:

  1. max = (Integer.MIN_VALUE /: arr) { max2 }

如你所见,Scala的简洁可以调整到一个很舒服的程度。不过,享受简洁的裨益之时,你必需确保你的代码没有变成密码——这里需要寻求一个适度的平衡。