「値」の渡し方

前項のFunctionプロシージャ」の説明で、値を渡すことをやっているので、見ていただければお判りだと思います。「Subプロシージャ」でも同様に値を渡すことができます。プロシージャ間の値の渡し方は「基本的なこと」なのですが、「基本操作」ではプロシージャが複数に渡るような例にまで行かないこともあり、こちらで説明しています。

子プロシージャを呼び出す時に「引き数」として渡す。




1.「参照渡し」
通常、何も指定せず(もしくはByRef指定)渡す場合は「参照渡し」となります。

'***************************************************************************************************
'   Functionプロシージャ(参照渡し)サンプル                          Module1(Module)
'
'   作成者:井上治  URL:https://www.ne.jp/asahi/excel/inoue/ [Excelでお仕事!]
'***************************************************************************************************
'変更日付 Rev  変更履歴内容------------------------------------------------------------------------>
'03/07/05(1.00)新規作成
'16/11/19(1.10)*.xlsm化の変更
'20/02/15(1.20)コード整理、標準化準拠作業
'***************************************************************************************************
Option Explicit

'***************************************************************************************************
'   ■■■ シート側から呼び出される処理 ■■■
'***************************************************************************************************
'* 処理名 :TEST
'* 機能  :元のプロシージャ
'---------------------------------------------------------------------------------------------------
'* 返り値 :(なし)
'* 引数  :(なし)
'---------------------------------------------------------------------------------------------------
'* 作成日 :2003年07月05日
'* 作成者 :井上 治
'* 更新日 :2020年02月15日
'* 更新者 :井上 治
'* 機能説明:
'* 注意事項:あくまでもサンプルです。
'***************************************************************************************************
Public Sub TEST()
    '-----------------------------------------------------------------------------------------------
    Dim strTEXT As String                                           ' 受け渡し文字列
    strTEXT = "あいうえお"
    ' 値を渡して、TEST2プロシージャを呼ぶ
    Call TEST2(strTEXT)
    ' 値が書き換わったか確認
    MsgBox strTEXT & "が戻ってきた!"
End Sub

'***************************************************************************************************
'   ■■■ サブ処理(Private) ■■■
'***************************************************************************************************
'* 処理名 :TEST2
'* 機能  :呼ばれるプロシージャ(参照渡し)
'---------------------------------------------------------------------------------------------------
'* 返り値 :(なし)
'* 引数  :Arg1 = 受け渡し文字列(String)              ※Ref参照
'---------------------------------------------------------------------------------------------------
'* 作成日 :2003年07月05日
'* 作成者 :井上 治
'* 更新日 :2020年02月15日
'* 更新者 :井上 治
'* 機能説明:
'* 注意事項:
'***************************************************************************************************
Private Sub TEST2(ByRef strTEXT2 As String)
    '-----------------------------------------------------------------------------------------------
    ' 値が渡ってきたか確認
    MsgBox strTEXT2 & "が渡ってきた!"
    ' 渡された値を書き換える
    strTEXT2 = "かきくけこ"
End Sub

'----------------------------------------<< End of Source >>----------------------------------------
この例は、「strTEXT」に「あいうえお」をセットして、子プロシージャ「TEST2」を呼び出しています。子プロシージャ「TEST2」側は、渡された内容は「strTEXT2」という変数で受け取っています。起動させて見ると、
ByRef渡しのサンプル結果
となり、「渡された値を書き換える」の所で元の「strTEXT」が「かきくけこ」に書き換わっているのかを呼び元プロシージャ側で確認できます。
呼ばれた側の子プロシージャ「TEST2」のカッコ内は、「ByRef strTEXT2」と宣言しているのですが、「ByRef」はVBAではデフォルトなので省略しても同じ意味になります。
この「ByRef」が参照渡しの宣言です。動きとしては、親プロシージャ側で宣言している「strTEXT」を子プロシージャ「TEST2」側の「strTEXT2」は参照しているだけで、実体は1つになっていることになります。
※この「ByRef」は省略せずに明示することをお勧めします。(VB.NETでは省略値が「ByVal」になっています)

2.「値渡し」
子プロシージャ側は、参照渡しではなく値として渡したい場合は、宣言時に「ByVal」を付けて宣言します。

'***************************************************************************************************
'   Functionプロシージャ(値渡し)サンプル                            Module1(Module)
'
'   作成者:井上治  URL:https://www.ne.jp/asahi/excel/inoue/ [Excelでお仕事!]
'***************************************************************************************************
'変更日付 Rev  変更履歴内容------------------------------------------------------------------------>
'03/07/05(1.00)新規作成
'16/11/19(1.10)*.xlsm化の変更
'20/02/15(1.20)コード整理、標準化準拠作業
'***************************************************************************************************
Option Explicit

'***************************************************************************************************
'   ■■■ シート側から呼び出される処理 ■■■
'***************************************************************************************************
'* 処理名 :TEST
'* 機能  :元のプロシージャ
'---------------------------------------------------------------------------------------------------
'* 返り値 :(なし)
'* 引数  :(なし)
'---------------------------------------------------------------------------------------------------
'* 作成日 :2003年07月05日
'* 作成者 :井上 治
'* 更新日 :2020年02月15日
'* 更新者 :井上 治
'* 機能説明:
'* 注意事項:あくまでもサンプルです。
'***************************************************************************************************
Sub TEST()
    '-----------------------------------------------------------------------------------------------
    Dim strTEXT As String                                           ' 受け渡し文字列
    strTEXT = "あいうえお"
    ' 値を渡して、TEST2プロシージャを呼ぶ
    Call TEST2(strTEXT)
    ' 値が書き換わったか確認
    MsgBox strTEXT & "が戻ってきた!"
End Sub

'***************************************************************************************************
'   ■■■ サブ処理(Private) ■■■
'***************************************************************************************************
'* 処理名 :TEST2
'* 機能  :呼ばれるプロシージャ(値渡し)
'---------------------------------------------------------------------------------------------------
'* 返り値 :(なし)
'* 引数  :Arg1 = 受け渡し文字列(String)
'---------------------------------------------------------------------------------------------------
'* 作成日 :2003年07月05日
'* 作成者 :井上 治
'* 更新日 :2020年02月15日
'* 更新者 :井上 治
'* 機能説明:
'* 注意事項:
'***************************************************************************************************
Private Sub TEST2(ByVal strTEXT2 As String)
    '-----------------------------------------------------------------------------------------------
    ' 値が渡ってきたか確認
    MsgBox strTEXT2 & "が渡ってきた!"
    ' 渡された値を書き換える
    strTEXT2 = "かきくけこ"
End Sub

'----------------------------------------<< End of Source >>----------------------------------------
このように、子プロシージャ「TEST2」側の「strTEXT2」の宣言の前に「ByVal」がある以外は参照渡しと全く同じです。起動させて見ると、
ByVal渡しのサンプル
となり、こちらは子プロシージャ側での値の書き換えが影響しないわけです。子プロシージャ「TEST2」側の「strTEXT2」は親プロシージャの「strTEXT」とは別の実体があって呼び出し時に値がコピーされてくる動作です。値を書き戻すといった動作はしないため、親プロシージャで宣言した変数は子プロシージャの影響を受けません。



これは、どちらが良いという問題ではなく、ケースによりこれをうまく利用するように注意する必要があるということですが、 あえて書き換えられた値を利用するということでない場合は「ByVal」を原則として考えた方が良いように思います。

モジュールレベル変数を使う。
プロシージャ内で宣言した変数は、そのプロシージャ内でしか参照できないことは「変数の宣言と初期化、有効(適用)範囲」で説明しました。 そこでモジュールレベル変数を利用すれば、プロシージャ間での値の引き渡しができることが判ります。
この場合は、親子プロシージャ間で宣言されている変数が一つしかないので、上の参照渡しと同じ結果になることははっきりしています。



但し、モジュールレベル変数の多用は良くないと言われています。 特に「プロシージャ間の受け渡し」ということだと、作成した本人は「他での喰い合いがない」ことが解っているので良いのですが、 後から他者が保守や調査用途でこのように仕組まれたソースコードを見た時に「他で書き換わらない」ことをいちいち確認しなければならなくなります。



特定「プロシージャ間の受け渡し」に限って用意したとしても、後からの機能改変で利用されてしまったりすることも多々あるので、 その時に想定外の動作になってしまうこともあります。 原則としては「変数」はできるだけ狭いスコープで用いるべきと考えるべきでしょう。