6.6 参数的位置记法
在Scala里,下划线(_
)可以表示函数值的参数。如果某个参数在函数里仅使用一次,就可以用下划线表示。每次在函数里用下划线,都表示随后的参数。先来看个例子:
FunctionValuesAndClosures/Underscore.scala
val arr = Array(1, 2, 3, 4, 5)
println("Sum of all values in array is " +
(0 /: arr) { (sum, elem) => sum + elem }
)
上面的代码里,用/:
方法计算数组元素的和。sum
和elem
各只用了一次,就可以省略这些名字,把代码写成这样:
FunctionValuesAndClosures/Underscore.scala
println("Sum of all values in array is " +
(0 /: arr) { _+_}
)
第一个出现的_
表示的是一个函数调用过程中持续存在的值,第二个表示数组元素④。或许,你会争辩说,这段代码简短生硬,丧失去了可读性——sum
和elem
这两个名字的存在是有益的。这是个合理的观点。因此,应该在让代码简洁而不失可读性的地方使用_
,就像下面这个例子:
④如果Scala无法确定类型,那么它会报错。如果发生了这种情况,可以为
_
提供类型,或退后一步使用带类型的参数名字。FunctionValuesAndClosures/Underscore.scala
val negativeNumberExists = arr.exists { _ < 0 }
println("Array has negative number? " + negativeNumberExists)
在某些有意义的地方,这种简洁还可以更进一步。假定有个函数可以得到两个数中的最大值。我们想用这个函数确定数组元素中最大的一个。我们从只在/:()
方法中使用它开始:
def max2(a: Int, b: Int) : Int = if (a> b)a else b
var max = (Integer.MIN_VALUE /: arr) { (large, elem) => max2(large, elem) }
我们把一对值(large
和elem
)传给max2()
方法,以确定哪个更大。计算结果最终会用来确定数组中的最大元素。用_
简化它可以写成这样:
max = (Integer.MIN_VALUE /: arr) { max2(_, _) }
_
不只可以表示一个参数,也可以表示整个参数列表。这样的话,就可以把max2()
改成下面这样:
max = (Integer.MIN_VALUE /: arr) { max2 _ }
在上面的代码里,_
表示整个参数列表,也就是说,(parameter1, parameter2)
。如果只是把接收到的东西传给下层的方法,甚至可以省下使用_
的繁文缛节。进一步简化上面的代码:
max = (Integer.MIN_VALUE /: arr) { max2 }
如你所见,Scala的简洁可以调整到一个很舒服的程度。不过,享受简洁的裨益之时,你必需确保你的代码没有变成密码——这里需要寻求一个适度的平衡。