Excel VBA Subプロシージャの()の中の変数の値、参照受け渡し方法

ExcelVBA-実用編

VBAでSubプロシージャの()の中の変数についてご説明します。

プロシージャ間で変数を使用して、値や参照を渡すことが出来ます。

この変数を渡すことで「Public変数」などの広域変数の乱用などを控える事が出来るようになります。

ですが、DimやPublicなど宣言セレクションで宣言することで、同じことができるため広域変数を使用してしまいがちになりますが、可読性やメンテナンス性が低下してしまいます。

最初は難しく感じますが、慣れるとそんなに難しくありませんのでぜひ覚えてみてください。

基本的な変数の使い方については下記記事をご覧ください。

1.Subプロシージャの変数の記述方法

まずは細かい話は抜きにして、受け渡す方と受け取る方のそれぞれの記述方法を説明します。

渡す方の記述方法

値を渡す方の記述方法です。

こちらは呼び出したい「Call プロシージャ名()」の()の中に渡したい変数を記述します。

Sub Sample1()

Dim 渡す変数 As String

渡す変数 = "値"

Call Sample2(渡す変数)

End Sub
受け取る方の記述方法

こちらは受け取る方の記述方法です。

こちらは少し特徴があり、「Sub プロシージャ名()」の()の中に受け取る変数を記述します。

その際、いくつか記述方法があります。

それは「ByVal 変数 As 型」、「ByRef 変数 As 型」などです。

違いについては後ほど説明します。

Sub Sample2(ByVal 受け取る変数 As String)

MsgBox 受け取る変数

End Sub
複数記述する方法

渡す方と受け取る方の記述は上記の通りですが、複数の値を受け渡す方法もあります。

次のように「Call プロシージャ名(値,値,値)」とカンマで区切って渡します。

Sub Sample3()

Dim 渡す変数1 As String
Dim 渡す変数2 As String
Dim 渡す変数3 As String

渡す変数1 = "値"
渡す変数2 = "は"
渡す変数3 = "これです。"

Call Sample4(渡す変数1, 渡す変数2, 渡す変数3)

End Sub

受け取る方も、カンマで区切って宣言して受け取ります。

Sub Sample4(ByVal 受け取る変数1 As String, ByVal 受け取る変数2 As String, ByVal 受け取る変数3 As String)

MsgBox 受け取る変数1 & 受け取る変数2 & 受け取る変数3

End Sub

Sample3を実行すると、次のように表示されます。

2.ByValとByRefの違いについて

上記で出た受け取るプロシージャの宣言時の「ByVal」と「ByRef」の違いについて説明したいと思います。

変数の宣言方法によって渡された値の挙動が変わります。

また、ByValとByRefは省略することができ、省略した場合は自動的にByRefを使用したことになります。

ByValとByRefの違いは受け取った後に「値の変更が可能か不可か」の違いだと思ってください。

ByValを値渡し、ByRefを参照渡しといい、渡すものが変数に格納された値なのか変数そのものなのかという違いがあります。

わかりづいらいので、サンプルコードで挙動の違いを見ていきます。

ByValのサンプル

まずは値を渡すByValについてです。

Sample5で変数に10を代入して、Sample6で10倍にしたあとに、メッセージボックスに表示してみます。

Sub Sample5()

Dim MyInt As Long

MyInt = 10

Call Sample6(MyInt)

MsgBox MyInt

End Sub
Sub Sample6(ByVal MyInt As Long)

MyInt = MyInt * 10

End Sub

Sample5で渡した値がSample6で計算されましたが、値は書き換わっていません。

ByRefのサンプル

次は参照を渡すByRefです。

Sub Sample7()

Dim MyInt As Long

MyInt = 10

Call Sample8(MyInt)

MsgBox MyInt

End Sub
Sub Sample8(ByRef MyInt As Long)

MyInt = MyInt * 10

End Sub

ByRefは受け取った方で計算した結果が反映されて表示されました。

参照渡しの場合は渡した変数を渡しただけで、中身を書き換わってしまします。

3.ByValとBaRefの使い分け

上記の違いである程度挙動の違いが分かったかと思います。

「値」を変更しない、結果を戻さない場合は「ByVal」を使用します。

「値」を変更する、処理された結果を返してもらう場合は「ByRef」を使用する感じで使い分けるといいと思います。

正直なところ、変数や値を受け渡しすることで広域変数を削減できますが、受け渡しの頻度が多くなりすぎるとそれはそれであちこちにプロシージャが飛び回ってしまいます。

結果、可読性やメンテナンス性も落ちてしまします。

そのため、作成するツールの規模や設計に応じて使い分ける事が大事です。

4.ちょっとしたサンプルコード

最後に実際に使いそうなサンプルコードの紹介です。

VBAで最終行や最終列を取得する事は頻繁に行われます。

そのためSubプロシージャに最終行を判定するシート名や列を渡す方法です。

Sub Sample9()

Dim MaxRow As Long
Dim Sh As Worksheet

Set Sh = Worksheets("Sheet1")

MaxRow = 2

Call Sample10(Sh, MaxRow)

MsgBox "最終行は" & MaxRow & "です"

End Sub
Sub Sample10(ByRef Sh As Worksheet, ByRef MaxRow As Long)

MaxRow = Sh.Cells(Rows.Count, 1).End(xlUp).Row

End Sub

このように記述すると毎回「MaxRow = .Cells(Rows.Count, 1).End(xlUp).Row」と記述しなくても、「Call Sample10(Sh, MaxRow)」で取得可能になります。

今回は1行なのでメリットがわかりにくいですが、もっと長いコードですとメリットがわかるかもしれません。

タイトルとURLをコピーしました