変数は、宣言のしかたによって、使える場所が限られます。これを、変数の適用範囲といいます。変数の適用範囲を理解するには、VBAの"プロシージャ"と"モジュール"という概念を理解しなければなりません。
プロシージャとは、Sub ○○~End SubまたはFunction ○○~End Functionなど、マクロの最小実行単位です。
''2つのSubプロシージャ「Sample1」「Sample2」と ''1つのFunctionプロシージャ「myCalc」がある Sub Sample1() ''何かの処理 End Sub Sub Sample2 ''何かの処理 End Sub Function myCalc(n As Long) ''何かの処理 End Function
モジュールとは、こうしたプロシージャを記述する場所です。一般的には、標準モジュールにプロシージャを作成することが多いですね。この標準モジュールは、その名の通りモジュールです。ブックには、標準モジュール以外にも、いくつかのモジュールが用意されています。VBEの[オブジェクトエクスプローラ]に表示される「Sheet1」や「ThisWorkbook」などイベントを記述するモジュールをまとめてDocumentモジュールと呼びます。また、「Sheet1」や「Sheet2」などワークシートのイベントを記述するところをシートモジュール、ブックのイベントを記述する「ThisWorkbook」をブックモジュールと個別に呼ぶこともあります。ほかにも、UserFormを挿入するとFormモジュールが使えるようになります。
今までの解説で登場した変数は、次のようにプロシージャの中で宣言されていました。
Sub Sample15() Dim buf As String buf = "tanaka" End Sub
このように、プロシージャの中で宣言した変数は、宣言したプロシージャの中でしか使用できません。
Sub Sample16() Dim buf As String buf = "tanaka" End Sub Sub Sample17() MsgBox buf ''×使用できない(エラーになる) End Sub
こうした「プロシージャの中で宣言した変数」をプロシージャレベル変数などと呼びます。まぁ、呼び名はどうでもいいです。大事なことはイメージすることです。
では、同じ変数を、複数のプロシージャで使用するにはどうしたらいいでしょう。そんなときは、変数をモジュールの宣言セクションで宣言します。宣言セクションとは、モジュールの、最も上に作成したプロシージャよりも、さらに上の部分です。
Dim buf As String Sub Sample18() buf = "tanaka" ''○使用できる End Sub Sub Sample19() MsgBox buf ''○使用できる End Sub
宣言セクションで宣言した変数は、そのモジュール内のすべてのプロシージャで使用可能です。こうした変数をモジュールレベル変数などと呼びます。まぁ、呼び名はどうでもいいです。大事なことはイメージすることです。
もう少し視点を広げてみましょう。
いま、標準モジュール「Module1」と標準モジュール「Modukle2」があったとします。Module1の宣言セクションで宣言した変数は、Module1内のすべてのプロシージャで使用できます。しかし、その変数はModule2では使用できません。
Module1の宣言セクションで、Dimステートメントを使って宣言した変数は、宣言したModule1内でしか使用できません。もし、宣言したモジュール以外の、別のモジュールでもその変数を使用したいときは、Dimステートメントではなく、Publicステートメントを使って宣言します。
Publicステートメントを使って宣言した変数は、宣言したモジュールはもちろん、すべてのモジュール内の、すべてのプロシージャで使用できます。こうした変数をパブリック変数などと呼びます。まぁ、呼び名はどうでもいいです。大事なことはイメージすること・・・しつこいですか。
変数は、使用する範囲を考えて、適切な方法で宣言してください。パブリック変数はすべてのプロシージャで使えるからといって、何でもかんでもパブリック変数にしてはいけません。たとえば、次のコードをご覧ください。
Sub Sample20() Dim i As Long, buf As String buf = InputBox("シート名は?") For i = 1 To Worksheets.Count Worksheets(i).Name = buf & i Next i End Sub Sub Sample21() Dim i As Long, buf As String For i = 1 To 10 buf = Cells(i, 1) If Left(buf, 1) = "A" Then Cells(i, 3) = "OK" End If Next i End Sub
上の2つのプロシージャでは、どちらも変数iと変数bufを使っていますが、それぞれ関連しない、別の処理をするプロシージャです。両方のプロシージャで同じ「Dim i As Long, buf As String」という宣言をするからといって、これを
Dim i As Long, buf As String Sub Sample22() buf = InputBox("シート名は?") For i = 1 To Worksheets.Count Worksheets(i).Name = buf & i Next i End Sub Sub Sample23() For i = 1 To 10 buf = Cells(i, 1) If Left(buf, 1) = "A" Then Cells(i, 3) = "OK" End If Next i End Sub
のように、2つの変数をモジュールレベル変数で宣言してはいけません。これは、重大なバグを生む原因になります。モジュールレベル変数や、パブリック変数は、"楽をする"ためにある仕組みではありません。複数のプロシージャ、または複数のモジュール間で、変数を共有しなければならないケースで使うべきものです。