VBAで「同じ変数名なのに値が違う」「別のSubで変数が使えない」といった謎の挙動に困ったことはありませんか?その原因はスコープ(変数の使える範囲)の理解不足にあります。
この記事でわかること:
- スコープ(変数の使える範囲)とは何か
- ローカル変数・モジュール変数・パブリック変数の違い
Dim・Static・Publicの使い分け- 実務でありがちなスコープの落とし穴と対策
スコープ(変数の使える範囲)を理解するには?
スコープとは、変数がどこで使えるか(=使える範囲)のことです。VBAでは変数を宣言した場所によって、使える範囲がまったく変わります。
たとえば、次のような疑問に明確に答えるためにスコープの理解が必要です。
- その変数、別のプロシージャでも使える?
- その変数、モジュールをまたいで使える?
- その変数、マクロが終わった後も値が残ってる?
VBAの3種類のスコープを知るには?
VBAには主に3つのスコープがあります。
| スコープ | 宣言の場所 | 使えるプロシージャ | 変数の寿命 |
|---|---|---|---|
| ローカル変数 | プロシージャ内 | そのSubの中だけ | マクロの実行中だけ |
| モジュール変数 | モジュールの先頭 | 同じモジュール内のすべてのSub | マクロが終わるまで |
| パブリック変数 | 標準モジュールの先頭(Publicで宣言) | すべてのモジュール・すべてのSub | Excelが閉じられるまで |
1. ローカル変数(プロシージャ内のみ)
Sub Test1()
Dim msg As String
msg = "こんにちは"
MsgBox msg
End Sub
msg は Test1 の中だけで使える変数です。他のSubからはアクセスできません。基本はローカル変数を使うのが安全です。
2. モジュール変数(モジュール全体で共有)
Dim cnt As Long ' モジュールの先頭で宣言
Sub CountUp()
cnt = cnt + 1
MsgBox cnt
End Sub
Sub ResetCount()
cnt = 0
End Sub
モジュールの先頭(Sub の外)で Dim を使って宣言すると、同じモジュール内のすべてのSubで共有できます。他のモジュールからは使えません。
3. パブリック変数(全モジュール共通)
Public userName As String ' 標準モジュールの先頭
Sub SetName()
userName = "佐藤"
End Sub
Sub ShowName()
MsgBox userName
End Sub
Public を使うとすべてのモジュール・プロシージャからアクセスできる「グローバル変数」になります。便利な反面、意図せず値が上書きされるリスクがあるため、慎重に使いましょう。
Staticで変数の値を保持するには?
Static を使うと、プロシージャ内の変数でも実行が終わった後も値が保持されます。
Sub TestStatic()
Static num As Long
num = num + 1
MsgBox num
End Sub
このコードを何度も実行すると、表示される数値が1・2・3…と増えていきます。通常の Dim 変数はSubが終わると値がリセットされますが、Static はそのまま保持されます。
スコープの落とし穴を避けるには?
落とし穴1:Publicを使ったら実行順に依存してバグに
Public msg As String
Sub Step1()
msg = "準備完了"
End Sub
Sub Step2()
MsgBox msg ' Step1を実行していないと空のまま
End Sub
グローバル変数に依存した処理は、実行順序によってバグが起きやすくなります。
落とし穴2:モジュール変数が意図せず変わっていた
Dim cnt As Long ' モジュール変数
Sub A()
cnt = 1
End Sub
Sub B()
cnt = cnt + 1 ' AとBどちらでもcntが変わる
End Sub
複数のSubで同じ変数を共有すると、どこで値が変わったかわかりにくくなります。
スコープを正しく設計するには?
迷ったときは次の3ルールを意識しましょう。
- ルール1:基本はローカル変数 →
DimをSubの中で使い、その中だけで完結させる - ルール2:複数のSubで共有する場合のみモジュール変数 → 同じ処理対象の変数を共通化するときに使う
- ルール3:Publicはできるだけ避ける → テスト用途や特殊な場面に限定。名前も短すぎるものはNG
まとめ
- スコープとは変数の「使える範囲」のこと
Dim(プロシージャ内)→ ローカル変数、Subが終わるとリセットDim(モジュール先頭)→ モジュール変数、同じモジュール内で共有Public→ パブリック変数、全モジュールで共有・Excelが閉じるまで保持Static→ プロシージャ内でも値を保持し続ける特殊な変数- 基本はローカル変数を使い、必要なときだけスコープを広げるのが安全な設計
よくある質問
ローカル変数とモジュール変数、どちらを使うべきか迷います
基本はローカル変数(Subの中でDim宣言)が安全です。複数のSubで同じ変数を参照・変更する必要がある場合のみ、モジュール変数を使うようにしましょう。
Publicとモジュール変数の違いは何ですか?
モジュール変数は同じモジュール内のSubのみで使えます。Publicを使うとブック内の全モジュール・全Subからアクセスできます。Publicはより影響範囲が広いため、使うときは慎重に。
Staticはどんなときに使いますか?
「何回ボタンを押したか」のようなカウンターや、「前回の処理結果を次回に引き継ぎたい」といった場面で使います。通常の業務マクロでは使う機会は少ないですが、知っておくと役立ちます。
同じ変数名をローカルとモジュールで使ったらどうなりますか?
Sub内でローカル変数が宣言されている場合は、そちらが優先されます。同じ名前でもスコープが異なれば別の変数として扱われるため、意図しない挙動の原因になります。可能な限り名前は重複させないようにしましょう。
グローバル変数(Public)は使わないほうがいいですか?
使うこと自体は問題ありませんが、どこからでも変更できるためバグの温床になりやすいです。テスト用途や、設定値のように一度だけセットして変更しない値に限定するのが理想的です。
動画で学びたい方へ
「記事を読んでも、実際に自分で書けるか不安…」という方には、動画で基礎からじっくり学べる講座がおすすめです。
VBAが初めての方を前提に、つまずきやすいポイントを先回りして解説しています。サンプル動画は無料でご覧いただけます。



