Excel VBA | 変数のスコープ(適用範囲)

Excel VBA VBA
スポンサーリンク

初心者向けに噛み砕いて、実際に手を動かして学べるように例題・練習問題付きで詳しく説明します。

ざっくり要点

  • 「どこで変数を宣言するか」で、その変数が使える範囲(スコープ)が決まります。
  • プロシージャ(Sub / Function)内で宣言するとそのプロシージャだけで使える(ローカル)。
  • プロシージャの外(モジュールの先頭)で宣言すると、そのモジュール内のすべてのプロシージャで使える(モジュールレベル)。

1. まずは「プロシージャ内で宣言した変数(ローカル変数)」

説明:Dim をプロシージャの中で書くと、その変数は「そのプロシージャ内だけ」で有効になります。別のプロシージャからは見えません。
例:

Option Explicit

Sub TestA()
    Dim x As Integer
    x = 5
    MsgBox "TestA の x = " & x   ' → 5
End Sub

Sub TestB()
    MsgBox "TestB の x = " & x   ' エラー:変数 x は定義されていない(Option Explicit があるとコンパイルエラー)
End Sub
VB

ポイント:

  • Option Explicit を使うと、宣言していない変数はエラーになります(タイプミスや勘違いを防げるので必須レベルでおすすめ)。

2. 「モジュール(プロシージャの外)で宣言した変数(モジュールレベル)」

説明:モジュールの先頭に Dim(または Private)で宣言すると、そのモジュール内の全てのプロシージャから同じ変数を使えます。状態を共有したいときに使います。
例:

Option Explicit
Dim counter As Integer   ' モジュールレベル

Sub Init()
    counter = 10
    MsgBox "Init: counter = " & counter   ' → 10
End Sub

Sub AddFive()
    counter = counter + 5
    MsgBox "AddFive: counter = " & counter  ' Init 実行後に実行すると → 15
End Sub
VB

ポイント:

  • 同じモジュール内のプロシージャ同士で値を受け渡すのに便利。だが使い方を誤ると「どこで値が変わったか分からない」バグの原因にもなります。

3. ローカル変数とモジュール変数が同名の場合(シャドーイング)

説明:モジュールの外で宣言した num と、あるプロシージャ内で同名 num を再び Dim すると、プロシージャ内の num が優先(ローカルが勝つ)で、モジュール変数は別物として扱われます。
例:

Option Explicit
Dim num As Integer   ' モジュール変数

Sub A()
    num = 10     ' モジュール変数に 10 が入る
End Sub

Sub B()
    Dim num As Integer   ' ローカル変数(ここではモジュール変数とは別)
    num = 3
    MsgBox "B の num = " & num   ' → 3(ローカル)
End Sub

Sub C()
    num = num + 5
    MsgBox "C の num = " & num   ' A を実行していれば → 15(A で 10、C で +5)
End Sub
VB

ポイント:

  • 同名を使うと混乱するので、モジュール変数にはプレフィックスをつける(例:m_counter)など、命名ルールを決めよう。

4. モジュールを超えて共有したいとき(別モジュール/全プロジェクトで使いたいとき)

  • そのモジュールだけでなくプロジェクト全体(他のモジュール)で使いたい場合は、Public を使います。例:Public gValue As Integer を標準モジュールのトップに置けば、どのモジュールのプロシージャからも参照可能です。
    (参考ページではモジュールレベルまで触れていますが、Public の取り扱いもよく使われます。)

注意:

  • Public 変数は便利だが、どこからでも書き換えられるため、大規模コードでは副作用管理が難しくなります。

5. 実際に試すときの手順(Excel でのやり方)

  1. Excel を開く → Alt + F11 で VBA エディタを開く。
  2. メニューの「挿入」→「標準モジュール」を追加。
  3. そこに上のサンプルコードを貼り付ける。
  4. F5 か、プロシージャ名を選んで Run で実行。メッセージボックスやイミディエイトウィンドウ(Ctrl+G)で結果を確認する。
    Option Explicit をオンにしておくと安全です:モジュールの先頭に Option Explicit を書く。)

6. よくある落とし穴(初心者がハマりやすい点)

  • 変数の宣言漏れ(タイプミスで別の変数を作ってしまう)→ Option Explicit を必ず使う。
  • 「どのプロシージャが変数を変えたのか分からない」→ モジュールレベル/Public 変数をむやみに増やさない。代わりに引数や戻り値でデータを渡す設計を検討。
  • 同名で別変数が存在(ローカルとモジュールで同名)→ 意図せぬ挙動になる。命名規則で回避。
  • グローバル変数を多用するとバグの追跡が困難に。

7. 練習問題

問題1(基本)
A モジュールに以下を書いて、順に RunInitRunInc を実行してどう表示されるか答えよ。

Option Explicit
Dim v As Integer

Sub RunInit()
    v = 2
    MsgBox "RunInit: v = " & v
End Sub

Sub RunInc()
    v = v + 3
    MsgBox "RunInc: v = " & v
End Sub
VB

解答1:RunInit → 「RunInit: v = 2」, その後 RunInc → 「RunInc: v = 5」。

問題2(シャドーイング確認)
次を順に A, B, C 実行。各 MsgBox が何を表示するか。

Option Explicit
Dim num As Integer

Sub A()
    num = 7
End Sub

Sub B()
    Dim num As Integer
    num = 1
    MsgBox "B: num = " & num
End Sub

Sub C()
    MsgBox "C: num = " & num
End Sub
VB

解答2:B → 「B: num = 1」, C → 「C: num = 7」(A を先に実行している前提。A を実行していなければ C は 0)。

問題3(少し応用)
別モジュール(Module1 と Module2)に分けて Public g As Integer を宣言するとどうなるか試してみよう(Module1: Public g As Integer、Module1 Sub が g = 100 をセット、Module2 から MsgBox で表示)。結果:Module2 からも g が 100 と表示される(モジュールを跨いで共有される)。


まとめ(実践的なアドバイス)

  • まずは Option Explicit を全モジュールに書く。
  • できるだけ「値は渡す(引数/戻り値)」で済ませ、モジュール/Public 変数は必要最小限に。
  • モジュール変数を使うなら m_mod_ などプレフィックスで区別すると読みやすい。
  • コードが大きくなったら、作用域(スコープ)を意識してモジュール分割・命名規則を徹底すること。
タイトルとURLをコピーしました