VBAの変数のスコープを完全解説!プロシージャレベルとモジュールレベルの違い
生徒
「先生、さっきのプログラムで使った『変数』を、別のマクロでも使おうとしたらエラーが出てしまいました。一度作った箱はどこでも使えるんじゃないんですか?」
先生
「それは『スコープ』というルールが関係しています。変数には、それぞれ『使える有効範囲』が決まっているんですよ。」
生徒
「有効範囲……?箱を置く場所によって、中身が見えたり見えなかったりするってことですか?」
先生
「その通りです!どこで宣言するかによって、そのマクロの中だけで消えてしまうか、他のマクロからも使えるかが変わります。詳しく解説しますね。」
1. 変数の「スコープ」とは?
Excel VBA(エクセル・ブイビーエー)におけるスコープ(Scope)とは、宣言した変数が「プログラムのどこから参照できるか」という有効範囲のことです。プログラミングの世界では、すべての変数をどこからでも使えるようにしてしまうと、思わぬところで値が書き換わってしまうトラブルが起きやすくなります。
そのため、VBAでは「この箱はこの部屋の中だけで使う」「この箱はこの建物全体で使う」といったように、利用できる範囲を制限する仕組みが備わっています。これを正しく理解することが、エラーの少ない綺麗なコードを書くための第一歩です。
2. プロシージャレベル変数(ローカル変数)
もっとも一般的なのが、プロシージャレベル変数です。これは Sub から End Sub の中で宣言する変数のことで、そのマクロ(プロシージャ)の中だけで有効です。プログラミング用語では「ローカル変数」とも呼ばれます。
例えるなら、自分の「カバンの中」のようなものです。自分のカバンの中身は自分しか触れませんし、家に帰ってカバンを片付ければ(マクロが終われば)、中身の存在は忘れてしまいます。
Sub MyMacro1()
' この中で宣言した変数はMyMacro1専用です
Dim myName As String
myName = "田中"
MsgBox myName & "さんの処理を開始します。"
End Sub
Sub MyMacro2()
' ここでMyMacro1のmyNameを使おうとするとエラーになります
' MsgBox myName ' ←これは動かない!
End Sub
このように、他のマクロに影響を与えたくない一時的な計算や名前の保存には、必ずプロシージャレベル変数を使います。
3. モジュールレベル変数(Private変数)
同じモジュール(プログラムを書くシートのようなもの)の中にある複数のマクロで共通して使いたい箱が必要なときは、モジュールレベル変数を使います。
宣言する場所がポイントで、Sub の中ではなく、コードの一番上の部分(宣言セクション)に書きます。キーワードは Dim または Private を使います。
これは「家の中の共有棚」のようなイメージです。家族(同じモジュール内のマクロ)なら誰でもその棚にある箱を出し入れできますが、外の人(別のモジュール)からは見えません。
' モジュールの最上部に書きます
Dim sharedUser As String
Sub SetUserName()
sharedUser = "佐藤"
MsgBox "ユーザーを" & sharedUser & "に設定しました。"
End Sub
Sub ShowUserName()
' SetUserNameで入れた値をそのまま使えます
MsgBox "現在のユーザーは" & sharedUser & "です。"
End Sub
4. パブリックレベル変数(プロジェクトレベル)
もっとも広い範囲で使えるのが、パブリックレベル変数です。これは、異なるモジュール間でも共有できる変数です。宣言するときに Public というキーワードを使います。
これは「公園のベンチ」や「公共の施設」のようなものです。そのエクセルファイル(プロジェクト)に含まれるすべてのプログラムから、いつでも読み書きが可能です。非常に便利ですが、どこで中身が変わったか分かりにくくなるため、初心者のうちは使いすぎに注意しましょう。
' 標準モジュールの最上部にPublicと書きます
Public TotalCount As Long
Sub CountUp()
TotalCount = TotalCount + 1
End Sub
5. なぜスコープを意識する必要があるの?
パソコンを触ったことがない方にとって、「全部Publicにすれば楽じゃない?」と思うかもしれません。しかし、スコープを意識しないと以下のような問題が発生します。
- 名前の衝突: いろいろな場所で同じ「i」という変数を使っていると、Publicにしているせいで他のマクロの数字まで書き換わってしまう。
- メモリの無駄: 広いスコープの変数は、エクセルを閉じたりプログラムをリセットしたりするまでメモリ(作業領域)を占領し続けます。
- バグの発見が遅れる: 「どこかで数字が勝手に変わっているけど、どのマクロが犯人かわからない!」という状態になりやすい。
基本は「できるだけ狭い範囲(プロシージャレベル)」で使い、どうしても必要なときだけ広げるのが、プログラミングの鉄則です。
6. 変数の寿命(ライフタイム)についても知ろう
スコープとセットで覚えておきたいのが寿命(ライフタイム)です。変数がいつ作られて、いつ消えるかという時間の流れのことです。
| 変数の種類 | いつ生まれるか | いつ消えるか |
|---|---|---|
| プロシージャレベル | マクロが動いた時 | End Subに到達した時 |
| モジュールレベル | ブックを開いた時など | ブックを閉じた時など |
プロシージャレベル変数は、マクロが終わるたびに中身が空っぽになります。次に動かしたときは、また「新しい箱」としてスタートするのです。逆に、値をずっと保持しておきたい場合は、上のレベルで宣言する必要があります。
7. スコープを間違えたときのエラーと対処法
もし、有効範囲の外で変数を使おうとすると、VBAは「変数が定義されていません」というエラーを出します。パソコン初心者の方はこのメッセージを見ると驚いてしまいますが、「箱が見つからないよ!」と教えてくれているだけです。
対処法は2つです。一つは、そのマクロの中でも Dim を使って新しく宣言すること。もう一つは、宣言する場所をモジュールの最上部に移動させて、スコープを広げることです。どちらが適切か、その変数の役割を考えて判断しましょう。
8. 良いプログラムを書くためのスコープ活用術
変数のスコープを使い分けられるようになると、あなたのVBAスキルは格段にアップします。最後に、初心者が心がけるべきポイントをまとめます。
- マクロの中で完結する計算は、必ず
Subの中でDimする。 - 複数の
Subで「同じ設定値」を使いたいときだけ、モジュールの上の方で宣言する。 - 変数名は、スコープが広いものほど丁寧な名前(例:
UserSettingNameなど)にする。
最初は難しく感じるかもしれませんが、「箱の見える範囲」を意識して書くだけで、複雑な自動化ツールもスムーズに作れるようになります。まずは小さなマクロで、変数の有効範囲を実験しながら試してみてくださいね!