所谓可选参数(optional parameter),是指在调用过程/函数时可以不必提供参数值的参数。回顾我们前面讨论过的一些函数,譬如格式化日期时间的函数 FormatDateTime,其一般形式为:FormatDateTime(dateexpr[, NamedFormat])在该函数中,日期表达式 dateexpr 是必须要提供的,而 NamedFormat 可以不必提供,所以是可选参数。例子如下:Debug.Print FormatDateTime(Now)Debug.Print FormatDateTime(Now, vbLongDate)Debug.Print FormatDateTime(Now, vbLongTime)
对于可选参数,之所以可以不必提供参数值,是因为在函数定义时,我们已经提供了默认参数值。例子如下。Function IsLeapYear(Optional ByVal y As Integer = 2026)IsLeapYear = (y Mod 4 = 0) And Not (y Mod 100 = 0 And y Mod 400 <> 0)End Function
在这个例子中,我们定义了一个判断闰年的函数 IsLeapYear,该函数的唯一参数 y 是一个可选参数(由 Optional 指明),如果调用者不提供参数值,则参数 y 取 2026。Sub LeapYearTest()Debug.Print IsLeapYear() ' 判断公元 2026 年是否闰年Debug.Print IsLeapYear(300) ' 判断公元 300 年是否闰年Debug.Print IsLeapYear(2028) ' 判断公元 2028 年是否闰年End Sub
(2) 由上面的例子可以看出,可选参数的声明格式是: Optional parameter = default_value其中 parameter 是正常参数的声明,其格式是: ByVal | ByRef pname As Type其中 ByVal | ByRef 表示或者是 ByVal,或者是 ByRef,pname 是参数名。default_value 表示可选参数的默认值,必须是常数。可选参数的默认值也是可选的,意思是 Sub/Function 声明中也可以不指定可选参数的默认值。对于我们上面的例子,则必须指定默认值,因为函数体中必须依据该参数的值才能得出结果。如果 Sub/Function 可以不依赖可选参数的值,那就可以不指定参数的默认值。在 FormatAddress 函数中,只有地址参数 sAddress 是必须的,sProvince 和 sCity 都是可选的,这两个可选参数都没有提供默认值,这也就意味着,如果调用者没有提供参数值,则相应的参数在函数体中将不可用。我们在函数体中用 IsMissing 这个 VBA 函数来判断可选参数是否有值。IsMissing 返回一个 Boolean 值来表明一个参数是否有值。其一般格式为:其中,argname 是一个可选参数名。如果 argname 有值,则 IsMissing 返回 False,否则,返回 True。- 可选参数必须位于所有必须参数之后,不能在可选参数之后再有必须参数的声明。
- 所有参数值必须按照 Sub/Function 声明中的顺序给出,如果一个可选参数前面的可选参数没有值,也要用逗号(,)表明前面的参数,如:
- FormatAddress("大河路30号", , "北京市")
"北京市"前面的 sProvince 参数没有指定值,也要用逗号(,)表明 sProvince 的位置。这种按位置指定参数的方式,在有多个可选参数的情况下,有时候会很麻烦。VBA 提供了可以按名字指定参数的办法。这就是有名参数。所谓有名参数(named arguments),就是以“名值对”的形式指定参数值,亦即将参数值与参数名通过特殊的赋值号(:=)绑定在一起。传统的参数指定方式是实参与形参通过位置的对应来实现绑定,有名参数则是直接通过形参与实参的结合实现绑定。这样一来,调用 Sub/Function 时,参数的指定就与形参声明时的位置无关了。从这个例子可以看出,使用有名参数与否,与 Sub/Function 的参数声明无关,同样的 FormatAddress 函数,既可以使用如图 1 的无名参数形式(位置相关),也可以使用如图 2 的有名参数形式(位置无关)。注:所谓”位置无关“的意思是,既不需要为无值参数保留位置,也不需要按照参数声明的顺序指定实际参数值。使用有名参数,虽然有些”啰嗦“,但有时候确实很方便,优点之一就是”自文档化“(self-documenting)。