はじめに
VBAでサブルーチンに引数を渡す際、「参照渡し(ByRef)」と「値渡し(ByVal)」という2つの方法があることをご存知でしょうか?この2つは似て非なるもので、違いを理解しないままでいると、「呼び出したマクロに変数を渡したら、元の値まで変わってしまった!」という予期せぬバグの原因になります。
一言で違いを説明するなら、こうです。
- 参照渡し (
ByRef
): 変数そのもの(原本)を渡す。 - 値渡し (
ByVal
): 変数の値だけをコピーしたもの(コピー)を渡す。
この記事では、この重要な違いを、具体的なコード例を使って分かりやすく解説します。
参照渡し (ByRef
):原本を渡す
ByRef
は “By Reference” の略で、「参照によって渡す」という意味です。サブルーチンに変数の「場所(メモリアドレス)」を教えるため、サブルーチン内での変更が、呼び出し元の元の変数に直接反映されます。
VBAでは、ByVal
や ByRef
を省略すると、デフォルトで ByRef
になります。
ByRef
のサンプルコード
' === メインの実行マクロ ===
Sub Main_ByRef_Example()
Dim originalValue As String
originalValue = "元の値"
' 結果をC2セルに出力
Worksheets("Sheet1").Range("C2").Value = originalValue
' サブルーチンを呼び出す
Call ModifyValue_ByRef(originalValue)
' 呼び出し後の値をC3セルに出力
Worksheets("Sheet1").Range("C3").Value = originalValue
End Sub
' --- ByRefで引数を受け取るサブルーチン ---
' ByRefは省略可能だが、明記すると分かりやすい
Private Sub ModifyValue_ByRef(ByRef textData As String)
' 受け取った引数の値を変更する
textData = "値が変更されました"
End Sub
実行結果
Main_ByRef_Example
を実行すると、以下のようになります。
- C2セル:
元の値
- C3セル:
値が変更されました
<– 元の変数の値が変わっている!
これは、ModifyValue_ByRef
が originalValue
変数の原本を直接書き換えたためです。
値渡し (ByVal
):コピーを渡す
ByVal
は “By Value” の略で、「値によって渡す」という意味です。サブルーチンに変数の値のコピーだけを渡すため、サブルーチン内でそのコピーをいくら変更しても、呼び出し元の元の変数には何の影響もありません。
ByVal
のサンプルコード
' === メインの実行マクロ ===
Sub Main_ByVal_Example()
Dim originalValue As String
originalValue = "元の値"
' 結果をD2セルに出力
Worksheets("Sheet1").Range("D2").Value = originalValue
' サブルーチンを呼び出す
Call ModifyValue_ByVal(originalValue)
' 呼び出し後の値をD3セルに出力
Worksheets("Sheet1").Range("D3").Value = originalValue
End Sub
' --- ByValで引数を受け取るサブルーチン ---
' ByValキーワードを明記する必要がある
Private Sub ModifyValue_ByVal(ByVal textData As String)
' 受け取った引数(コピー)の値を変更する
textData = "値が変更されました"
End Sub
実行結果
Main_ByVal_Example
を実行すると、以下のようになります。
- D2セル:
元の値
- D3セル:
元の値
<– 元の変数の値は変わっていない!
これは、ModifyValue_ByVal
が originalValue
のコピーだけを受け取って変更したため、原本には影響がなかったことを示しています。
まとめと使い分け
参照渡し (ByRef ) | 値渡し (ByVal ) | |
渡すもの | 変数の原本(場所) | 変数の値のコピー |
元の変数 | 変更される | 変更されない |
宣言方法 | ByRef を付けるか、省略する | ByVal を付ける |
用途 | サブルーチンに値を変更して返してほしい場合 | 元の値を保護したい場合 |
意図しない値の変更は、追跡が難しいバグの温床になります。そのため、サブルーチンが受け取った値を変更する必要がない場合は、安全のために常に ByVal
を明記するのが、堅牢なプログラムを書くための良い習慣と言えます。