vba-training-07-アイキャッチ

VBAトレーニング-07 [関数操作について-②]-[ByVal(値渡し)とByRef(参照渡し)の違い]

このページで学習出来る事

 前回は関数の[Sub]と[Function]の違いについて説明しましたが、今回は関数への値の渡し方について説明をします。

 値の渡し方には[ByVal(値渡し)]と[ByRef(参照渡し)]の二種類が存在し、それぞれ違った動きをしますので、変数の動きに気を付けながら見ていきたいと思います。

学習内容

  • [ByVal(値渡し)]と[ByRef(参照渡し)]の違い

この学習で使用するエクセルファイルはここからダウンロードできます。

  


サンプルコード

 [sample-07.xlsm]を開いて、中に書かれているコードを確認しましょう。
 今回のコードでは、二種類の関数[subByValAction]と[subByRefAction]が書かれています。それぞれ変数の値がどう変化をしていくか見ていきます。

 このファイルをそのまま使用しても構いませんし、新しくエクセルファイルを作って、自身でコードを記載して動かしても構いません。(直接コードを書いた方が覚えやすいので、時間がある方は書く練習もしてみましょう)

Sub main()
    Dim tempNum As Integer
    
    tempNum = 10
    Call subByValAction(tempNum)
    Debug.Print (tempNum)

    Call subByRefAction(tempNum)
    Debug.Print (tempNum)
End Sub

Private Sub subByValAction(ByVal tempNum As Integer)
    tempNum = 50
    Debug.Print (tempNum)
End Sub

Private Sub subByRefAction(ByRef tempNum As Integer)
    tempNum = 50
    Debug.Print (tempNum)
End Sub

コードの解説 sub main()部分

‘引数に[tempNum]を設定し[subByValAction]関数を呼び出しています。
‘呼び出したい関数の前に[Call]を付けることで、関数が呼び出せます。
Call subByValAction(tempNum)

‘引数に[tempNum]を設定し[subByRefAction]関数を呼び出しています。
Call subByRefAction(tempNum)

  

コードの解説 Sub subByValAction()部分

‘変数の前に[ByVal]を指定し、値渡しで変数を受け取れるよう設定しています。
Private Sub subByValAction(ByVal tempNum As Integer)

  

コードの解説 Sub subByRefAction()部分

‘変数の前に[ByRef]を指定し、参照渡しで変数を受け取れるよう設定しています。
Private Sub subByRefAction(ByRef tempNum As Integer)

  


[ByVal(値渡し)]での処理確認

 [ByVal(値渡し)]とは変数の値を関数へ渡すという意味で、イメージとしては[コピー&ペースト]に近いです。
変数の値をコピーして関数に渡す。そんなイメージです。

 実際の動きを確認するために、[Debug.Print]の所でブレークポイントを設定して実行してみましょう。
 [subByValAction]関数の中にあるブレークポイントで止まったところで、ローカルウィンドウにある[tempNum]を確認すると、「10」という値を渡された[tempNum]が「50」となっているのが確認できます。

  


Sub関数(ByVal)からの戻り値について

 変数の確認が終わったら、ブレークポイントで止まっている状態から再度動かしてみましょう。
 次のブレークポイントで止まったら再度[tempNum]を確認すると、先ほど「50」であった数値が「10」に戻っていると思います。
 これは[subByValAction]関数の処理結果が[sub main()]に反映されていないために起こる現象です。

 どうして処理した結果が反映されないのかと言うと、前回も説明した通り「[Sub]で定義される関数は値を返さない」という特徴を持つ関数だからです。

  


[ByRef(参照渡し)]での処理確認

 次に[ByRef(参照渡し)]ですが、これは変数の値を関数へ渡すのではなく、変数の場所を参照させるという意味で、イメージとしては[ショートカットやリンク]に近いです。
 エクセルファイルのショートカットをメールで送るイメージです。ファイル自体を送っているのではなく、ファイルの場所を送っている感じです。

 それでは、ブレークポイントで止まっている状態から再度動かしてみましょう。今度は[subByRefAction]関数の中にあるブレークポイントで止まったところで確認出来ます。
 これは処理が関数[subByRefAction]に移ったことを意味します。

 続けてローカルウィンドウにある[tempNum]を確認すると「50」という数値が入っている事が確認できます。

  


Sub関数(ByRef)からの戻り値について

 次に参照渡しでの値の変化を確認するために、再度ブレークポイントで止まっている状態から動かしてみましょう。
 次のブレークポイントで止まった後に[tempNum]を確認すると、先ほどと同様に「50」の数値になっていると思います。

 これは[ByVal(値渡し)]と違い、[ByRef(参照渡し)]の特徴により起こる現象です。
 先ほども説明しましたが、[ByRef(参照渡し)]はファイルのショートカットのようなイメージです。ショートカットで開いたファイルを上書き保存すると、元ファイルが更新されるのと同じ動きが、この[ByRef(参照渡し)]でも起きているのです。

 この場合、[tempNum]という変数を参照していますので、その参照先にて値を変更したら、参照元の[tempNum]も同様に値が変更されている事になります。

  


最後に([ByVal(値渡し)]と[ByRef(参照渡し)]の使い分け)

 今回は関数へ値を渡す、二種類の方法について説明をしました。
 では、具体的にどのような場面で、[ByVal(値渡し)]と[ByRef(参照渡し)]を使い分ければ良いかというと、次の場面で[ByRef(参照渡し)]を使用し、それ以外は[ByVal(値渡し)]を使えば大きな問題にはなりません。

[ByRef(参照渡し)]を使用する場面

・再帰処理で処理内容を追っていく場合、トータルカウントを保持したい場合
・連続して複数の関数処理が行われる場合(メソッドチェーンなど)
・変数の値が大きい場合
・配列を渡す場合

 [ByRef(参照渡し)]を多用すると、どこのタイミングで値が変わるかを追うのが難しくなってきます。
 上記の様な限られた場面で使用するか、ポリシーを持って使用するように心がけてください。

  

 次回は、関数の[Private]と[Public]の違いについて説明したいと思います。

  

前回-関連記事

このページで学習出来る事  前回まではブックやシートオブジェクトの操作に関して解説をしてきましたが、6回目となる今回は、VBAの関数操作に関して説明をしていきます。  一般的にコードは書けば書くほど行数が長くなっていきますが、プロ[…]

vba-training-06-アイキャッチ
次回-関連記事

このページで学習出来る事  前回は関数の[ByVal(値渡し)]と[ByRef(参照渡し)]の違いについて説明しましたが、今回は関数の呼び出し方や[Private]と[Public]の違いについて説明していきます。  関数には[Privat[…]

vba-training-08-アイキャッチ