為 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