参照渡しと値渡し


複数のプロシージャ間でデータの受け渡しをするには次のようにします。

Sub Sample()
    Dim buf As String
    buf = "tanaka"      ''変数に文字列"tanaka"を入れる
    Call Proc1(buf)     ''プロシージャProc1の引数に変数を渡して呼び出す
End Sub
Sub Proc1(a As String)
    MsgBox a
End Sub

これはシンプルな例ですね。では、データ(値)を受け取ったプロシージャ(ここではProc1)で値を変更したらどうなると思いますか。

実際に試してみましょう。

Sub Sample()
    Dim buf As String
    buf = "tanaka"      ''変数に文字列"tanaka"を入れる
    Call Proc1(buf)     ''プロシージャProc1の引数に変数を渡して呼び出す
    MsgBox buf          ''変数の値を表示する
End Sub

Sub Proc1(a As String)
   a = "suzuki"         ''受け取った値を"suzuki"に変える
End Sub

変数bufの値が変わってしまいました。これは、「Sample」プロシージャから「Proc1」プロシージャへ変数そのものを渡したためです。このようなデータの渡し方を参照渡しと呼びます。

データの渡し方にはもう一つの方法があります。次のコードをご覧ください。

Sub Sample()
    Dim buf As String
    buf = "tanaka"      ''変数に文字列"tanaka"を入れる
    Call Proc1(buf)     ''プロシージャProc1の引数に変数を渡して呼び出す
    MsgBox buf          ''変数の値を表示する
End Sub

Sub Proc1(ByVal a As String)
   a = "suzuki"         ''受け取った値を"suzuki"に変える
End Sub

今度は「Proc1」でデータを変更しても「Sample」の変数bufは変化しませんでした。このように、他のプロシージャに変数そのものを渡すのではなく、変数の値だけを渡す方法を値渡しと呼びます。

両者の違いは「Proc1」プロシージャの引数宣言です。値が変化しなかった二度目の「Proc1」は、受け取る引数の定義にByValというキーワードを付けています。これは「Proc1」の引数として受け取る変数「a」は、値渡しで受け取るという意味です。

"参照渡し"とか"値渡し"というと、渡す側に違いがあるように感じますが、実際には引数をどのように受け取るかといった、プロシージャの定義がポイントなのです。

変数の値が変わってしまった最初のコードでは、引数の定義に何も指定していません。実は、引数を参照渡しで受け取るときは、引数の定義にByRefというキーワードを付けるのが基本ルールです。

Sub Sample()
    Dim buf As String
    buf = "tanaka"      ''変数に文字列"tanaka"を入れる
    Call Proc1(buf)     ''プロシージャProc1の引数に変数を渡して呼び出す
    MsgBox buf          ''変数の値を表示する
End Sub
''引数を参照渡しで受け取る Sub Proc1(ByRef a As String) a = "suzuki" ''受け取った値を"suzuki"に変える End Sub

ただし、ByRefとByValのどちらも指定しなかった場合には、ByRefが指定されたものとみなされます。引数の定義でデータの渡し方を省略すると、それは参照渡しになるということです。

参照渡しと値渡しの違いは、正確にはメモリ内で参照する場所が異なるのですが、そうした難しい話はともかく、イメージとしては次のような感じです。

参照渡しのイメージ

値渡しのイメージ

複数のプロシージャでデータを共有する方法は他にもあります。すべてのプロシージャで使用できる広域変数を使うのも手ですし、ワークシート上のセルやレジストリなどにデータを書き込んで、複数のプロシージャでそこを参照する方法もあります。どのやり方が最も優れているか…ということではなく、ケースに応じて適切な方法を使い分けるようにしましょう。