为 ByRef
默认修饰符
如果没有为参数指定修饰符,则通过引用隐式传递该参数。
Public Sub DoSomething1(foo As Long)
End Sub
Public Sub DoSomething2(ByRef foo As Long)
End Sub
foo
参数在 DoSomething1
和 DoSomething2
中传递 ByRef
。
小心! 如果你带着其他语言的经验来到 VBA,这很可能与你习惯的完全相反。在许多其他编程语言(包括 VB.NET)中,隐式/默认修饰符按值传递参数。
通过引用传递
-
当值传递
ByRef
时,过程接收对值的引用。Public Sub Test() Dim foo As Long foo = 42 DoSomething foo Debug.Print foo End Sub Private Sub DoSomething(ByRef foo As Long) foo = foo * 2 End Sub
调用上面的
Test
过程输出 84.DoSomething
被赋予foo
并接收对该值的引用,因此使用与调用者相同的内存地址。 -
当参考被传递
ByRef
,程序接收一个参考指针。Public Sub Test() Dim foo As Collection Set foo = New Collection DoSomething foo Debug.Print foo.Count End Sub Private Sub DoSomething(ByRef foo As Collection) foo.Add 42 Set foo = Nothing End Sub
上面的代码引发了运行时错误 91 ,因为调用者正在调用不再存在的对象的
Count
成员,因为DoSomething
被赋予对象指针的引用并在返回之前将其分配给Nothing
。
在呼叫站点强制 ByVal
在呼叫站点使用括号,你可以覆盖 ByRef
并强制传递参数 ByVal
:
Public Sub Test()
Dim foo As Long
foo = 42
DoSomething (foo)
Debug.Print foo
End Sub
Private Sub DoSomething(ByRef foo As Long)
foo = foo * 2
End Sub
无论是隐式还是显式指定 ByRef
,上述代码都输出 42。
小心! 因此,在过程调用中使用无关的括号很容易引入错误。注意过程名称和参数列表之间的空格:
bar = `DoSomething(foo)` 'function call, no whitespace; parens are part of args list DoSomething (foo) 'procedure call, notice whitespace; parens are NOT part of args list DoSomething foo 'procedure call does not force the foo parameter to be ByVal