8.8 特殊的函数调用形式
大多数你会遇到的函数和函数调用都会像你在本章到目前为止看到的那样。函数会有固定数量的形参,函数在调用时也会有相同数量的实参,而这些实参出现的顺序也会跟形参相同。
由于函数调用在Scala编程中的核心地位,对于某些特殊的需求,一些特殊形式的函数定义和调用方式也被加到了语言当中。Scala支持重复参数、带名字的参数和默认参数。
重复参数
Scala允许你标识出函数的最后一个参数可以被重复。这让我们可以对函数传入一个可变长度的参数列表。要表示这样一个重复参数,需要在参数的类型之后加上一个星号(*)。例如:
这样定义以后,echo可以用零到多个String参数调用:
在函数内部,这个重复参数的类型是一个所声明的参数类型的Seqs。因此,在echo函数内部,args的类型其实是Seq[String]。尽管如此,如果你有一个合适类型的数组,并尝试将它作为重复参数传入时,将得到一个编译错误:
要完成这样的操作,你需要在数组实参的后面加上冒号和一个_*符号,就像这样:
这种表示法告诉编译器将arr的每个元素作为参数传给echo,而不是将所有元素放在一起作为单个实参传入。
带名字的参数
在一个普通的函数调用中,实参是根据被调用的函数的参数定义,逐个匹配起来的:
在这个调用当中,100被匹配给distance,而10被匹配给time。100和10这两个实参是按照形参被列出的顺序匹配起来的。
带名字的参数让你可以用不同的顺序将参数传给函数。其语法是简单地在每个实参前加上参数名和等号。例如,下面的这个对speed的调用等同于speed(100,10):
用带名字的参数发起调用,实参可以在不改变含义的前提下交换位置:
我们还可以换用按位置和带名字的参数。在这种情况下,按位置的参数需要放在前面。带名字的参数最常见的场合是跟默认参数值一起使用。
缺省参数值
Scala允许你给函数参数指定默认值。这些有默认值的参数可以不出现在在函数调用中,对应的参数将会被填充为默认值。
示例8.3给出了这样的例子。printTime这个函数有一个参数out,其默认值为Console.out。
示例8.3 带默认值的参数
如果你用printTime()来调用这个函数,也就是不指定用于out的实参,那么out将会被设置为默认值Console.out。也可以用一个显式给出的输出流来调用这个函数。例如,可以用printTime(Console.err)来将日志发送到标准错误输出。
默认参数跟带名字的参数放在一起时尤为有用。在示例8.4中,函数functionTime2有两个可选参数。其中out参数有个默认值Console.out,而divisor参数有一个默认值1。
示例8.4 带有两个带默认值的参数的函数
函数printTime2可以用printTime2()来调用,这样两个参数都被填充为默认值。通过带名字的参数,这两个参数中的任何一个都可以被显式给出,而另一个将被填充为默认值。要显式地给出输出流,可以这样写:
而要显式地给出时间的除数,可以这样做: