為 ByRef

預設修飾符

如果沒有為引數指定修飾符,則通過引用隱式傳遞該引數。

Public Sub DoSomething1(foo As Long)
End Sub
Public Sub DoSomething2(ByRef foo As Long)
End Sub

foo 引數在 DoSomething1DoSomething2 中傳遞 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