和風スパゲティのレシピ

日本語でコーディングするExcelVBA

ByRefの引数にただの値や定数を渡したときの動き

ByRefで定義された引数にただの値や定数を渡したらどうなるかを検証します。

結論から言うと、ByValと同じように動きます。


例えば以下のようなByRef(参照渡し)のプロシージャを作ったとします。

Sub ByRefに変数を渡して値を更新してもらう()

    Dim x As Long
    x = 1
    
    Call 渡された変数に1を足す(x)

    Debug.Print x

End Sub

Sub 渡された変数に1を足す(ByRef 引数 As Long)
    引数 = 引数 + 1
End Sub

このときxの中身は1から2に書き換わり、
イミディエイトウィンドウには「2」が表示されます。


この「渡された変数に1を足す」というSubプロシージャに、
変数ではなくただの「1」を渡してみましょう。

Sub ByRefにリテラルを渡す()

    Call 渡された変数に1を足す(1)

End Sub

Sub 渡された変数に1を足す(ByRef 変数 As Long)
    引数 = 引数 + 1
    Debug.Print 引数
End Sub


このコードを実行してもエラーは出ず、
中見のDebug.Printではちゃんと「2」が出力されます。


このようにByRefで定義された引数にただの値(リテラル)を渡した場合は、
その値が代入された変数が作成されたかのように動きます。


では次に定数を渡してみましょう。

Sub ByRefに定数を渡す()

    Const x = 1
    
    Call 渡された変数に1を足す(1)
    
    Debug.Print x

End Sub

Sub 渡された変数に1を足す(ByRef 引数 As Long)
    引数 = 引数 + 1
    Debug.Print 引数
End Sub


このコードを実行すると、
イミディエイトウィンドウには「2」「1」と順番に表示されます。

呼び出したプロシージャの定数が書き換わることはもちろんなく、
渡されたプロシージャ内ではちゃんと変数として動いているのがわかります。


このように、ByRefで定義された引数に値(リテラル)や定数を渡したときは、
ByValと同じ(その値が入った変数が新しく作られる)動き
をしてくれます。


これは「ByRefとByValの違いがよくわからず、なんとなく省略して書いていた頃」を思い出してみると、

Function 足し算(x As Long, y As Long) As Long
    足し算 = x + y
End Function

こんなFunctionを作って、

Debug.Print 足し算(1, 2) ' ← 3が表示される

こんな実行をしても動いていたわけですから、
よくよく考えてみるとそりゃそうだという話かもしれませんね。


ちなみにこの仕様の活用方法として、

Sub ByRefに変数をByValとして渡す()

    Dim x As Long
    x = 1
    
    Call 渡された変数に1を足す((x))
    
    Debug.Print x

End Sub

Sub 渡された変数に1を足す(ByRef 引数 As Long)
    引数 = 引数 + 1
End Sub

このように「引数にカッコ()をつけて渡す」ことで、
ByRefで作られた引数に無理やりByValを渡すことができます。


※ より正確には、カッコをつけたことでその部分が「式」の扱いになり、
 その式の結果をプロシージャに渡していると理解してください。
 このカッコは「1+ ( 2 / 2 )」で使う計算の順序を決めるカッコと同じもので、
 Long型に対しては(x * 1)や(x + 0)と書いても同じことができます。


これを活用したいケースはかなりレアな気がしますが、
活用したとして、挙動、意図が読み取りづらいコードになると思います。

もし活用する場合はしっかり意図をコメントに残しておきましょう。