はじめに
エクセルVBAでマクロの作成をしていると、変数をつかうことが必須となってきます。マクロの作成において、変数を自在に扱えるようになればマクロでできることが大幅に広がってきます。むしろ実務的なレベルでの自動化などは変数を利用することが必須であると言えます。
この記事では、エクセルVBAの変数が扱えるようになった人向けに、変数のスコープ(有効範囲)と有効期限(代入された値やオブジェクトが保持される期間)について解説しています。
まず、変数のスコープ(有効範囲)とは、ひとことで言えばその変数がどの範囲で利用できるかを指定したものとなります。マクロの処理をそれぞれでパート(部品)化する上で知っておきたい内容であり、大規模で複雑なマクロであればあるほど、ひとつのプロシージャに大量のコードを書きこむ方法が絶対にダメであるとは言えませんが、それぞれの役割をもった処理がまとめて書かれていると、コード量も多くなるだけでなく、問題発生時の原因の抽出が難しくなることや、プログラム全体を把握しづらいものとなります。
そこで、それぞれの処理ごとにプロシージャや、モジュールの単位でプログラムをまとめていくことが大切であり、可読性を良くすることや、メンテナンスのしやすくすることは、マクロ全体の質の向上につながります。
また、このようなマクロを構築していく上では、それぞれのモジュールやプロシージャで共有したい値やデータがでてきます。例えば、あるワークシートを変数に代入する処理を何度も繰り返し書く必要はありません。目的のシートを共有できる変数に代入しておけばほかのモジュールやプロシージャからでもあつかうことができます。
一度、ワークシートを代入した変数を、ほかのモジュールであつかう必要も出てくるため、宣言した変数のスコープ(適用範囲)を意識する必要があります。スコープ(適用範囲)を指定して値やデータを共有することは、便利さと引きかえにマクロの実行エラーや、意図しない動作の発生を招くリスクも含まれるため、これらの事象を予防するためにも、それぞれの変数がもつスコープ(適用範囲)を理解したうえで活用することが求められます。
変数のスコープ(適用範囲)は大きく3つに分類されます。他のモジュールからもあつかえるスコープ(適用範囲)の変数をグローバル変数といい、これがもっともスコープ(適用範囲)が広いものです。次に同じモジュールの他のプロシージャからもあつかえるスコープ(適用範囲)のモジュールレベルの変数があり、さいごにプロシージャのなかだけでのみ利用する変数があり、こちらがもっともスコープ(適用範囲)が狭いものです。
この記事では、VBAの変数がもつスコープ(適用範囲)の指定方法と指定したときの動作について、または変数や定数の有効期限について紹介していきます。これらの内容について記事を読んだ人の理解が少しでも深まれば幸いです。
この記事の内容
ここでは、エクセルVBAであつかう変数のスコープ(適用範囲)について解説しています。エクセルVBAの変数のスコープや有効期限について以下の内容について知ることができます。
VBAの変数におけるスコープ(適用範囲)
まずは、それぞれの変数のスコープ(適用範囲)について紹介します。
プロシージャレベル変数のスコープ(適用範囲)
プロシージャの中で宣言する変数です。
Subや、FunctionからEnd SubやEnd Functionのなかで、「Dim」ステートメントをつけて宣言しているものがこちらに当たります。こちらの変数は、プロシージャレベルの変数と呼ばれ、変数を宣言したプロシージャ以外からの値の代入や、参照はできません。
なお、プロシージャレベルの変数は、プロシージャの処理が完了した時点で変数の値はリセット(初期化)されます。
プロシージャレベルの変数をあつかったサンプルマクロ
こちらのサンプルマクロでは、プロシージャを2つ作成しており「プロシージャレベルの変数()」を①、「プロシージャレベルの変数にアクセス()」を②としています。
①では、プロシージャレベル変数として、変数Pを宣言しています。また、①、②のいずれも、Debug.Printで変数Pの値を出力するコードを書いていますので実行してみます。
実行結果
①「プロシージャレベルの変数()」を実行すると以下がイミディエイトウィンドウに表示されます。
税込価格: 110 円です。
②「プロシージャレベルの変数にアクセス()」を実行すると「変数が定義されていない」エラーが発生します。

この結果から、変数Pを宣言していないプロシージャの②から、変数Pの値を参照することができないことがわかります。
モジュールレベル変数のスコープ(適用範囲)
プロシージャレベルの変数と異なり、モジュールの宣言セクションで宣言をする変数です。
宣言セクションで、Dimステートメントや、Privateステートメントをつかって宣言することでモジュールレベルの変数となります。
プロシージャレベルの変数と異なる点として、同じモジュールに書かれた他のプロシージャからでも値の代入や参照ができます。なお、モジュールレベルの変数の有効期限は、宣言したモジュールの処理が完了するまでです。
モジュールレベルの変数をあつかったサンプルマクロ
こちらのサンプルマクロでは、標準モジュールの宣言セクションで「M1」と「M2」という変数をDimステートメントと、Privateステートメントをつかって宣言しています。サンプルマクロの①を実行すると「M1」には1000が、「M2」には10000が代入されます。そして、それぞれの変数の値に1.1を掛けた数値をイミディエイトウィンドウに出力しています。
その後、Callステートメントをつかって②を呼び出して、変数「M1」と「M2」の値を2で割った数値に更新しています。イミディエイトウィンドウに表示された以下の出力結果から、それぞれの変数の値が出力できていることが確認できます。
なお、ここでのポイントですが、Callステートメントで②を呼び出すときに変数「M1」と「M2」を引数として指定していなくても変数に代入された値が保持できている点です。モジュールレベルの変数は、変数を宣言したモジュールの処理が完了するまでの間は値が保持されるため、②のプロシージャに処理が移っても変数の値は引き継がれています。
なお、変数の値がリセット(初期化)されるタイミングは、プロシージャ①が完了したタイミングです。

プロシージャ①から②を呼び出し、②が終了のしたあとで①が終了する順番になるね。
実行結果
税込価格: 1100 円です。
税込価格: 11000 円です。
税込価格: 550 円です。
税込価格: 5500 円です。
パブリックレベル変数のスコープ(適用範囲)
プロシージャレベルの変数と異なり、モジュールの宣言セクションで宣言をする変数です。宣言セクションで、Publicステートメントをつかって宣言することでパブリックレベルの変数となります。
Globalステートメントをつかっても同じ宣言が可能ですが、これは、VB(ビジュアルベーシック)の古いバージョンとの互換性のためにつかわれていたものが残っているためなので、VBAではPublicステートメントをつかうことが一般的です。また、Globalステートメントは標準モジュール以外に書きこむとエラーなり宣言はできません。
パブリックレベルの変数は、グローバル変数とも呼ばれ、対象となる変数を宣言したモジュール外からの値の代入や参照が可能です。なお、パブリックレベルの変数の有効期限はブック(ファイル)を閉じるまでです。
パブリックレベルの変数をあつかったサンプルマクロ
パブリックレベルの変数をあつかうマクロですが、ここでは標準モジュールを2つ準備します。「標準モジュール(変数のスコープ2_1)」の宣言セクションで宣言したパブリックレベルの変数に、値の代入や出力を実行してみます。
以下に、それぞれのモジュールに書いたプロシージャと動作について解説します。
上記のモジュールには、宣言セクションでPublicステートメントをつけて変数「G」を宣言しています。なお、今回はデータ型を文字列(String)型にしていますので、文字列を代入・参照していくマクロとなります。
また、こちらのモジュールは、2つのプロシージャを作成しています。コメントでそれぞれに①と②という番号づけしていますので、以降の説明にはこちらの番号を利用したいと思います。
まず、①のプロシージャを実行すると、変数「G」に「株式会社オブジェクト」も文字列を代入します。その直ぐ下の行において、変数「G」にイミディエイトウィンドウに出力する処理を行います。なお、ここでは社名である”オブジェクト”の部分のみを取り出す文字列操作処理を想定しており、Mid関数や、InStr関数をつかって出力する内容を操作しています。
続いて、Callステートメントをつかって、②のプロシージャを呼び出していますが、変数「G」を引数には指定していません。プロシージャ②のなかで、変数「G」に先ほど①のプロシージャで代入された値を更新し、①と同様にイミディエイトウィンドウに出力します。
さらに、Callステートメントをつかって、他のモジュールに書かれたプロシージャ(パブリックレベルの変数C)を呼び出す処理をします。
パブリックレベルの変数Bによって呼び出されたこちらのモジュールのプロシージャ③ですが、②と同じく変数「G」に代入された値を更新し、①と同様にイミディエイトウィンドウに出力しています。
それでは、実行結果を見てみましょう。
実行結果
オブジェクト
オブジェクト Plus One
オブジェクト Plus One ぷらす 2
オブジェクト Plus One ぷらす 2株式会社オブジェクト
オブジェクト Plus One ぷらす 2株式会社オブジェクト Plus One
オブジェクト Plus One ぷらす 2株式会社オブジェクト Plus One ぷらす 2
上の実行結果は、マクロを2回実行したものです。上が3行がプロシージャ①、②、③の1回目の実行結果で、4行目から6行目は、2回目の実行結果になります。
標準モジュール(変数のスコープ2_1)の宣言セクションで、publicステートメントをつかって宣言した変数「G」には、プロシージャ①の中で「株式会社オブジェクト」が代入されます。その後、プロシージャ②において「株式会社オブジェクト」に「Plus One」という文字列を付け加えています。さらにプロシージャ③では、「オブジェクト Plus One」に「ぷらす 2」の文字列を付け加える処理をしています。
この結果から、変数「G」に代入された値(文字列)は、プロシージャやモジュールが他のものに移ったあともリセット(初期化)されずに保持されていることがわかります。なお、2回目の実行結果からもわかるように、変数「G」に代入された値はマクロの処理が完了しても保持されており、実行を繰り返す度に文字列を付け加えていくことになります。
この結果から、パブリックレベルの変数の有効期限が確認できました。変数「G”」の値は、ブック(ファイル)を閉じることでリセット(初期化)されます。
このように、Publicステートメントで宣言した変数は、他のモジュールからも値の代入や出力が可能となりますので、プロジェクト全体で共通する変数などが必要なときに有効です。
パブリック・モジュールレベル変数をあつかう時の注意点
これまでの説明で、パブリックレベルの変数とモジュールレベルの変数は、他のモジュールやプロシージャからもあつかうことができることを説明しました。
ここでは、プロシージャレベルよりもスコープ(適用範囲)が広い、パブリックレベルやモジュールレベルの変数をあつかう際の注意点について紹介します。

変数のスコープ(適用範囲)を広げることのリスクについて紹介するよ。
パブリック・モジュールレベル変数名の重複
宣言セクションで宣言をするパブリック・モジュール変数を利用する場合は、変数名の重複に注意が必要です。宣言セクションで宣言した変数名と同じ変数を宣言した場合は、以下の画像のように「同じ適用範囲内で宣言が重複しています。」とエラーメッセージを表示し、コンパイルエラーが発生します。

パブリック・モジュールレベル変数名のつけかた
宣言セクションで宣言をするパブリック・モジュール変数を利用する場合は、マクロの処理が、プロシージャやモジュール間を越えたものになることが多いため、変数名からその変数がどのようなデータをあつかっているかを想像しやすいものにしておくことが望ましいです。
理由としては、スコープ(適用範囲)が広い変数は、プロシージャレベルの変数とちがい、変数を宣言しているプロシージャや、モジュールから離れたプロシージャで処理を実行することがあるため、可読性の低下が見込まれるためです。
他のプロシージャからパブリック・モジュールレベル変数を更新する
パブリックやモジュールレベルの変数は、他のプロシージャやモジュールからの影響をうける可能性があります。これは、スコープ(適用範囲)が広い変数のメリットの裏返しであり、他のプロシージャやモジュールから、値を操作(追加・変更・削除など)が出来てしまうことでマクロ制作者の意図しない値に書き換えられてしまうリスクとなります。
例えば、For NextやDo Loopなどの繰り返し処理の書きかたを紹介した記事でも触れたように、変数をつかって繰り返す回数を制御しているときに、他のプロシージャによってその変数が書き換えられたことで無限ループが発生する可能性があります。
他にも、データ型が異なる値を代入しようとして型が一致しないエラーなど、スコープ(適用範囲)が広い変数をあつかうことのリスクには注意が必要です。
「For Next」や「Do Loop」を使った繰り返し処理の書きかたは、過去の記事であつかっています。
以下のリンクより読むことができますので合わせてご覧ください。
パブリックレベルの変数は宣言したモジュールをわかるようにする
パブリックレベルの変数は、他のモジュール内のプロシージャによる影響をうけてしまう恐れがあるため、エラーが発生した場合は処理をさかのぼって、どこが原因でエラーになる処理が実行されているかを検証する必要がでてきます。
この作業を容易でスムーズにするためにも、パブリック変数に値を代入する、出力するなどの処理を実行する場合に、その変数を宣言したモジュールがわかるようにコードを書くことや、コメントに残すことが望ましいと言えます。
具体的には、以下のマクロにおける下線部分のようにコメントアウトをすることや、コード上でモジュール名を省略することが可能な場合であっても、敢えて書き残すことでその変数がどのモジュールで宣言されたのかが、ひと目でわかるようにする方法があります。
補足として、②のようにVBAのコードにモジュール(オブジェクト)名まで書くと、コードが長くなる可能性はあります。
ただ、コード量をなるべく減らし、スッキリさせて可読性を上げる行為は、マクロ全体を把握しやすくし、エラーの発生を予防する、機能拡大などのアップデートを容易にするなどの目的のための手段です。このケースの場合などで、モジュール名を敢えて書き残すことで「プログラムを見やすくする、理解を促す」という同じ目的に従ったものであれば誤りではなく、手段の選択だと言えるはずです。

コード量を減らすことが目的ではないということだね。
パブリックレベルの変数は使用しているプロシージャをわかるようにする
前項と同じく、パブリックレベルの変数をあつかって処理をしているプロシージャがわかるようにコメントを残すことで、意図しない動作の予防や、エラー発生時の検証作業、機能の拡大などのアップデートをしやすくする効果があるため、パブリックレベルの変数をあつかうプロシージャがわかるようにコメントを残すことも望ましいと言えます。
コメントの書きかたは自由ですが、わかりやすくするためにサンプルマクロでは、下線部のようにモジュール名(プロシージャ名)で利用とコメントアウトしています。
スクール選びにお悩みですか?
動画編集、ロボット、AIとテクノロジーの進化が目まぐるしい時代だからこそ身につけるなら即戦力のスキル。
豊富なコースが選べて、独自開発されたカリキュラムの採用で業界有数の学習継続率!
さらにスキル習得だけじゃない。卒業後の転職や副業まで激アツなサポートが無料!!
VBAの定数(Const)におけるスコープ(適用範囲)
これまでは変数のスコープ(適用範囲)について解説してきました。
エクセルVBAには、変数と同じく定数と呼ばれるものがあります。定数は変数と同じように宣言し、値を代入することで利用が可能であり、宣言の方法によって、スコープ(適用範囲)を指定することができます。
まずは、エクセルVBAにおける定数について簡単に説明します。
エクセルVBAにおける定数とは
定数は、変数と同じように宣言し、値を代入・出力することができます。宣言の方法はプロシージャまたは、モジュールの宣言セクションでおこないます。このとき、「Const」ステートメントを用いることで定数の宣言ができます。
定数は、変数のように多くの種類の値を代入することはできません。宣言できるデータ型は、Byte、Boolean、Integer、Long、Currency、Single、Double、Date、String、Variant型のいずれかになりますので、これらに当てはまる値を代入することができます。
変数であつかえるデータ型については、以下の記事でも紹介していますので合わせてご覧ください。
また、定数は宣言のタイミングで値を代入する必要があります。さらに、一度代入をしたあとでは値を更新することはできません。そのため定数は、宣言時に定めた値を利用する目的で使います。
エクセルVBAにおける定数宣言時の構文
[ Public | Private ] Const 定数名 as データ型 = 代入する値
※「Public」や「Private」ステートメントは、宣言セクションのみで使用可能です。
※宣言セクションでこれらのステートメントを省略した場合は「Private」になります。
※パブリックレベルの定数は、標準モジュールでのみ宣言可能です。ブックやシート、フォーム、クラスモジュールでは「Public」での宣言はできません。
エクセルVBAの定数の使いどころ
定数は、余程のことがない限り変わらない値をあつかう場合に利用すると良いでしょう。
以下に定数をあつかったサンプルマクロを作りましたので、参考にしてください。
定数をつかったサンプルマクロ

マクロの動作を分かりやすくするために、簡単な表(なんとかひょう)を作成し、薄い色のついたセルの部分を算出した結果を出力してみます。
こちらのマクロでは、定数はConstステートメントをつかって「Duty」という名前で宣言しています。また、データの型はDouble(小数点)型とし、宣言と同時に0.1を代入しています。
このように定数で指定しておくことで、たとえ将来的に税率が変わったとしても、定数に代入する値だけを更新すればマクロのアップデートができるため、複雑なコードが書きこまれた部分を触ることがないといったメリットがあります。
それでは、マクロを実行したあとの表の画像を見ていきます。
実行結果

各行の販売価格(税込)と販売価格、税額、販売価格(税込)の合計値を出力しました。
税率の部分は変数でも良いのでは?と思われるかもしれませんが、もちろん変数でも問題なく動作します。また、変数をつかった同じようなコードであった場合のアップデートにかかる手間も全く変わらないですが、定数をつかうことの利点は”一度代入した値は更新できない”ことであり、他のプロシージャからの処理の影響をうけないところだと言えます。この点がマクロに定数をつかう理由として、変数と区別ができる最大のポイントだと言えます。
さて、前置きが長くなってしまいましたが、次項からは定数のスコープについて解説していきます。
定数のスコープ(適用範囲)の種類
それでは、定数のスコープ(適用範囲)の種類ですが、変数と同様に以下のとおりとなります。
- プロシージャレベルのスコープ(適用範囲)
- モジュールレベルのスコープ(適用範囲)
- パブリックレベルのスコープ(適用範囲)
サンプルマクロとともに、それぞれを詳しくみていきましょう。
プロシージャレベルのスコープ(適用範囲)の定数
プロシージャ内で宣言したものは、こちらになります。
プロシージャ内でのみ定数の値の利用が可能であり、他のプロシージャやモジュールからは値の利用ができません。
プロシージャレベルのスコープ(適用範囲)の定数をあつかったサンプルマクロ
プロシージャ①を実行すると、価格を入力するインプットボックスを表示します。ここでは、100 を入力した結果を確認してみます。次にプロシージャ②ですが、こちらはプロシージャレベルの定数”PC”を異なるプロシージャから利用しようとしているため、「変数が定義されていない」エラーが発生します。
実行結果
プロシージャ①の実行結果
税込価格: ¥ 110 円です。
プロシージャ②の実行結果

定数名「PC」は、プロシージャレベルの定数であるため、宣言したプロシージャ①では利用が可能であり、他のプロシージャである②からでは、値の利用ができないことが確認できていることから、定数「PC」のスコープ(適用範囲)は宣言したとおり、宣言したプロシージャのみであることが確認できました。
モジュールレベルのスコープ(適用範囲)の定数
宣言したモジュール以外から定数の値が利用できます。各モジュールの宣言セクションにて「Private」ステートメントをつけることで宣言できます。また、「Public」や「Private」ステートメントを省略した場合は、モジュールレベル(Privateで宣言したものと同様)の定数となります。
モジュールレベルのスコープ(適用範囲)の定数をあつかったサンプルマクロ
プロシージャ①を実行すると、定数「MC」に代入された文字列”これはプライベート定数です。”を出力します。次にプロシージャ②では、プロシージャレベルの定数「MC」の値を更新しようとしていますが、こちらは「定数には値を代入できません」のエラーが発生します。
実行結果
プロシージャ①の実行結果
これはプライベート定数です。
プロシージャ②の実行結果

定数名「MC」は、モジュールレベルの定数であるためスコープ(適用範囲)から言えば、プロシージャ①だけでなく、プロシージャ②からも利用が可能です。しかし、プロシージャ②では、定数「MC」に代入された値を更新するコードを書いているためにエラーが発生する結果となっています。
なお、プロシージャ②の定数「MC」の値を更新するコード部分である「MC = “MCの文字列を書き換えました。” 」をコメントアウトすると、実行時エラーは発生せずにプロシージャ①と全く同じ結果となります。
パブリックレベルのスコープ(適用範囲)の定数
宣言したモジュール以外から定数の値が利用できます。標準モジュールの宣言セクションにて「Public」ステートメントをつけることで宣言できます。ただし、パブリックレベルの定数は標準モジュール以外では宣言できません。
パブリックレベルのスコープ(適用範囲)の定数をあつかったサンプルマクロ
定数「GC」はパブリックレベルの定数であるため、他のモジュールからでも値を利用できます。つまりプロシージャ①と③については、宣言時に代入した文字列である”これはパブリック定数です。”が表示できます。
さらに、定数「GC」のスコープ(適用範囲)から言えば、宣言元であるモジュールに含まれるプロシージャ②でも利用ができるはずですが、プロシージャ②には定数「GC」の値を更新するコードを書いているため、実行時エラーが発生します。
実行結果
プロシージャ①と③の実行結果
これはパブリック定数です。
プロシージャ②の実行結果

定数「GC」はパブリックレベルのスコープ(適用範囲)であるため、他のモジュール(標準モジュール2)にあるプロシージャ③から利用できていることがわかります。なお、パブリックレベルの定数については、標準モジュール以外で宣言しようとすると、VBEで構文エラーのようにあつかわれるため注意が必要です。
定数のスコープ(適用範囲)の種類と注意点まとめ
ここまでで、エクセルVBAの定数におけるスコープ(適用範囲)についての解説と、サンプルマクロを通して実際の動作を確認してきました。以下の表に定数のスコープ(適用範囲)の特徴と注意点をまとめましたので参考にしてください。
宣言場所 | ステートメント | 値の代入時期 | 値の更新 | 宣言できるデータ型 |
---|---|---|---|---|
宣言セクション ※標準モジュールのみ宣言可能 |
Public | 宣言と同時 | 不可 | Byte、Boolean、Integer、Long、Currency、Single、Double、Date、String、Variant型に限る |
宣言セクション | Private | |||
プロシージャの中 | Const |

定数は変わらない値を代入しておくものだね。
オンラインスクールで現役エンジニアのサポートがあるテックアカデミーがおすすめ。
スキマ時間に学べて仕事も保証。必ず副業、始められます。まずは無料でプログラミング体験
VBAの変数や定数の有効期限について
変数は宣言する方法によって使用できる期間があり、これを変数の有効期限と言います。
変数の有効期限は、変数の宣言方法によって異なります。プロシージャのなかで宣言した変数(プロシージャレベル変数)は、宣言したプロシージャの処理が完了した時点で初期化します。プロシージャレベル変数のスコープ(適用範囲)のまま、プロシージャの処理が完了しても変数の値を保持したいときには、「Static」ステートメントを使います。
また、標準モジュールの宣言セクションで宣言したモジュール変数のうち、「Dim」や「Private」で宣言したものは、そのモジュールの処理が完了するまでが変数の有効期限となり、「Public」で宣言したものはブック(ファイル)を閉じるまで値が保持される有効期限となります。
標準モジュールで宣言した変数の有効期限をまとめると以下のとおりです。
モジュール種別 | 宣言する場所 | ステートメント | スコープ(適用範囲) | 有効期限 |
---|---|---|---|---|
標準モジュール | プロシージャの中 | Dim | 宣言プロシージャ内 | プロシージャの処理完了まで |
Static | ブック(ファイル)を閉じるまで | |||
宣言セクション | Dim | 宣言モジュール内 | モジュールの処理完了まで | |
Private | ||||
Public | すべてのモジュール内 | ブック(ファイル)を閉じるまで |
変数の有効期限の一覧は動作を確認した上で記載しています。ただし、標準モジュールの変数の保持がどういった動作により破棄されるのかは、本記事を書くうえで参考にした資料上でも予想の範囲とされています。そのため、マクロの安全な運用を考えるのであれば、変数の有効期限を完全に信用することはせずにワークシートなどの信頼性の高い形で保存することが勧められています。
また、上記の表は標準モジュールで宣言したときの変数の有効期限です。標準モジュール以外のモジュールでは動作が異なるものが存在します。例えばクラスモジュールで「Public」をつかった変数の有効期限は、そのモジュールの処理が完了するまでとなっており、標準モジュールで宣言した場合と異なった結果となっています。
Staticステートメントでプロシージャレベル変数の有効期限を拡張する
Staticステートメントで宣言した変数は、宣言したプロシージャのマクロが完了しても、代入した変数の値が保持されるようになります。
Staticステートメントの使いかた
Staticステートメントは、プロシージャ内でのみ利用が可能です。プロシージャのなかで以下の構文に従って宣言します。
Static 変数名 As データ型

Dimステートメントの部分をStaticに変えるだけだよ。
Staticステートメントで宣言した変数をつかったサンプルマクロ
Staticステートメントで各データ型の変数を宣言すると以下のとおりです。Staticで宣言した変数に値を代入して、イミディエイトウィンドウに出力して値が保持されることを確認してみます。
上記のサンプルマクロは、Sample1~6とSampleSheetとSampleRangeという名前の変数を「Static」ステートメントをつけて宣言しています。パッと見たところコードの量は多いですが、中身のマクロの処理は単純なもので、それぞれの変数を宣言して値やオブジェクトを代入や参照し、出力するといったシンプルなものです。

変数(箱)を作って、中に値を入れてそれを出しているだけだよ。
それでは、サンプルマクロの実行結果をみてみましょう。
実行結果(1回目)
Sample1は 1
Sample2は 5
Sample3は 文字列
Sample4は 1:2:3
Sample5は A:B:C
Sample6は あ:い:う
SampleSheetは Sheet1
SampleRangeは SampleRangeのセル
イミディエイトウィンドウを確認すると、それぞれに値やオブジェクトが代入されていることがわかります。それでは、このマクロをもう一度実行してみるとどうなるでしょうか。
実行結果(2回目)
Sample1は 2
Sample2は 10
Sample3は 文字列文字列
Sample4は 2:4:6
Sample5は AA:BB:CC
Sample6は ああ:いい:うう
SampleSheetは Sheet2
SampleRangeは SampleRangeのセル2
2回目の実行により、1回目で変数に代入された値が保持されていることがわかります。それぞれの変数のうごきについては、以下のとおりになります。
プロシージャのマクロの実行が完了しても、変数の値が保持されていることが、2回目の実行結果から確認できます。なお、Staticで宣言した変数がリセット(初期化)されるタイミングは、ブックを閉じたとき、モジュールにプロシージャを追加するなどのを変更をしたとき、実行時エラーが発生したときです。
VBAの配列のスコープ(適用範囲)
VBAの変数・定数については値を1つ代入することができますが、ここからは複数の値を代入できる配列に関するスコープ(適用範囲)について解説します。配列と言っても変数の1つなので、難しく考える必要はありません。
なお、配列は定数で宣言することができないため、ここでは定数について考える必要はありません。(調べてみたところ、配列でArray関数やSplit関数を使って定数の配列のようなものは作れるようですが、変則的な方法となるのでここでは言及を控えておきます。)
プロシージャレベル配列のスコープ(適用範囲)
プロシージャの中で宣言する複数の値を代入することができる配列(変数)です。配列も変数の1つなので、動作は変数で紹介したものと同じです。
SubやFunctionから、End SubやEnd Functionのなかで、Dimステートメントをつけて宣言します。変数とちがう点は、宣言文の変数名に添え字をつけるところです。
静的配列では、宣言時に添え字で要素数を記入し、動的配列では”()”のみをつけておきます。なお、プロシージャで宣言した配列のスコープ(適用範囲)はプロシージャの範囲になるため、宣言したプロシージャ以外からの値の代入や、参照はできません。
なお、プロシージャレベルの配列は、プロシージャの処理が完了した時点で変数の値はリセット(初期化)されます。
配列については、別の記事でも紹介しているのでそちらも参考にしてください。
プロシージャレベルの配列をあつかったサンプルマクロ
こちらのサンプルマクロでは、標準モジュール1(プロシージャレベルの配列1)に2つのプロシージャを書いています。プロシージャレベルの配列1(①)では、静的配列である「配列C」と動的配列である「配列D」を宣言して、それぞれに値を代入したあとでイミディエイトウィンドウに出力してみます。
ここであつかっている静的配列の「配列C」は、1次元配列で3つの要素をもっていて、動的配列である「配列D」は3行×3列の要素をもつ2次元配列になります。
一方、プロシージャレベルの配列2(②)では、配列C・配列Dともに宣言文は書かずに、値の出力をするコードのみとしています。
既にマクロ内に実行結果をコメントアウトしていますが、プロシージャ①と②それぞれの実行結果をみていきましょう。
実行結果
プロシージャ①の実行結果
164
160
161
NOCCHi : 1988/09/20 : Blood / A
a-chan : 1989/02/15 : Blood / A
KASHIYUKA : 1988/12/23 : Blood / A
イミディエイトウィンドウに出力された内容です。上から3行が「配列C」の出力結果、それ以降が「配列D」の出力結果です。プロシージャ①で宣言した配列に値の代入と値の出力の処理を書いていますので、当然ながら問題なく実行が可能です。
プロシージャ②の実行結果
以下の画像のとおり「変数が定義されていない」エラーが発生します。

プロシージャ①で宣言した「配列C」と「配列D」はいずれもプロシージャレベルのスコープ(適用範囲)ですので、プロシージャ②のなかに出力に指定した配列(変数)は存在していません。そのため実行時エラーが発生していて、スコープ(適用範囲)のとおりプロシージャ②からは値の代入も出力はできません。
モジュールレベル配列のスコープ(適用範囲)
プロシージャレベルの配列と異なり、モジュールの宣言セクションで宣言をする変数です。
宣言セクションで、Dimステートメントや、Privateステートメントをつかって宣言することでモジュールレベルの配列となります。
配列も変数の1つですので、宣言方法は同じですが宣言文の変数名に添え字をつけることで配列となります。なお、静的配列では、宣言時に添え字で要素数を記入し、動的配列では”()”のみをつけておきます。
プロシージャレベルの配列と異なる点として、同じモジュールに書かれた他のプロシージャからでも値の代入や参照ができます。なお、モジュールレベルの配列の有効期限は、宣言したモジュールの処理が完了するまでです。
モジュールレベルの配列のスコープ(適用範囲)をあつかったサンプルマクロ
以下の2つのモジュールで検証してみます。モジュールレベルでの検証になりますので、宣言セクションで配列を宣言するモジュールである①と、その配列に値を代入・出力の実行を試みる別のモジュール②の2つを作成して、それぞれを実行して動作を確認してみます。
宣言セクションでは静的・動的の2つの配列を宣言しています。これらの配列は「Private」ステートメントをつけているため、モジュールのスコープ(適用範囲)となることから配列を宣言しているモジュールにあるプロシージャからであれば値の代入や出力ができます。
さて、マクロの動作のながれについての説明ですが、配列の「M静的配列B」の添え字は(2)を指定しているため、3つの要素を持てる配列になっています。ここに3つの文字列(キャラクターの名前)を代入したあと、イミディエイトウィンドウに「M静的配列B」の値を出力してみます。
続いて、もう一つの配列である「M動的配列B」は、3行×4列の2次元配列に再定義しています。そしてこの「M動的配列B」にそれぞれのキャラクターのプロフィール情報(身長・年齢・体重)を代入していきます。
こちらも先ほどと同じく、「M動的配列B」の値をイミディエイトウィンドウに出力してみます。
こちらは先ほどのモジュールとは別のモジュール「標準モジュール(配列のスコープ2)
」に処理を書いています。
こちらのプロシージャで実行する処理の内容は、使用する値はちがうものの、配列を宣言したモジュールとほぼ同じで「M静的配列B」と「M動的配列B」に値の代入と出力を試みます。
実行結果
猪名寺乱太郎 と 摂津ノきり丸 と 福富しんべヱ は人気アニメのキャラクターです。
猪名寺乱太郎 は身長が 136㎝ で年齢は 10歳 で体重は 30㎏です。
摂津ノきり丸 は身長が 140㎝ で年齢は 10歳 で体重は 34㎏です。
福富しんべヱ は身長が 125㎝ で年齢は 10歳 で体重は 67.5㎏です。
イミディエイトウィンドウの実行結果の1行目は「M静的配列B」の値を出力してみた結果です。2行目から4行目までが「M動的配列B」の値を出力した結果です。
これによりモジュールで宣言した2つの配列が、プロシージャで利用できていることが確認できました。
コンパイルエラーが発生します。
以下の画像のように「Sub または Function が定義されていません。」のエラーが表示されます。

この結果から、モジュールレベルのスコープ(適用範囲)で宣言した配列は、他のモジュールから利用できないことが確認できました。
パブリックレベルの配列のスコープ(適用範囲)
プロシージャレベルの変数(配列)と異なり、モジュールの宣言セクションで宣言をする変数です。宣言セクションで、Publicステートメントをつかって宣言することでパブリックレベルの配列となります。
配列は変数の1つですので、変数の宣言方法と同じですが、添え字を書く必要があります。添え字とは配列がもつ要素数ですので、宣言する配列の大きさを添え字で指定していることになります。
この大きさを宣言時に配列名の右側に書きますが、具体的な数値で指定してあるものを静的配列、”()”だけを指定してあるものを動的配列と呼びます。
パブリックレベルの変数(配列)は、グローバル変数とも呼ばれ、対象となる変数を宣言したモジュール外からの値の代入や参照が可能です。なお、パブリックレベルの変数の有効期限はブック(ファイル)を閉じるまでです。
パブリックレベルの配列のスコープ(適用範囲)をあつかったサンプルマクロ
モジュールレベルの時と同様に、2つのモジュールを作成して検証してみます。
パブリックレベルでの検証になりますので、宣言セクションで配列を宣言するモジュールである①と、その配列に値を代入・出力の実行を試みる別のモジュール②の2つを作成して、それぞれを実行して動作を確認してみます。
上記のモジュールでは、宣言セクションにてパブリックレベルのスコープ(適用範囲)の配列を2つ宣言しています。配列名からでもわかりますが、「G静的配列A」は静的配列で、「G動的配列A」は動的配列です。
「G静的配列A」は、文字列型で3つの要素をもつことができる配列であるため、文字列を代入してイミディエイトウィンドウに値の出力する処理をしています。
また「G動的配列A」は、3行×2列の配列に要素の大きさを再定義したのち、繰り返しと条件分岐をつかって1列目には「G静的配列A」の値と文字列”温泉”をつなぎ合わせたものを代入し、2列目には新たに文字列を代入して、最後のDo Loop文で値の出力処理をしています。
こちらのモジュールでは、宣言セクションで配列の宣言は行っていません。ですが、標準モジュール(配列のスコープ1)においてパブリックレベルのスコープ(適用範囲)の配列が宣言されていますので、「G静的配列A」と「G動的配列A」をあつかうことができます。
このモジュール(配列のスコープ2)で処理している内容は、代入する値はちがっているものの、標準モジュール(配列のスコープ1)と同じですので詳しい説明は割愛しますが、パブリックレベルのスコープ(適用範囲)の配列は、宣言したモジュール以外からでも値の代入と出力ができることが確かめられるかを見てみたいと思います。
実行結果
有馬、草津、下呂と言えば日本3名泉である。
有馬温泉 は 兵庫県 にあります。
草津温泉 は 群馬県 にあります。
下呂温泉 は 岐阜県 にあります。
宣言セクションで2つの配列を宣言し、プロシージャの中で値を代入して、イミディエイトウィンドウに出力しています。
出力された結果の1行目が「G静的配列A」に代入された値を、2から4行目までが「G動的配列A」に代入した値をつかって文章を表示することができました。
松島、天橋立、宮島と言えば日本3景である。
松島 は 宮城県 にあります。
天橋立 は 京都府 にあります。
宮島 は 広島県 にあります。
プロシージャ、モジュールレベルのケースと実行結果は異なり、宣言セクションで配列は宣言してなくとも、パブリックレベルのスコープ(適用範囲)の配列に対して、値の代入と出力ができています。
出力された結果の1行目が「G静的配列A」に代入された値を、2から4行目までが「G動的配列A」に代入した値をつかって文章を表示することができました。
スクール選びにお悩みですか?
動画編集、ロボット、AIとテクノロジーの進化が目まぐるしい時代だからこそ身につけるなら即戦力のスキル。
豊富なコースが選べて、独自開発されたカリキュラムの採用で業界有数の学習継続率!
さらにスキル習得だけじゃない。卒業後の転職や副業まで激アツなサポートが無料!!
VBAの構造体(ユーザー定義型)のスコープ(適用範囲)
これまで変数(配列を含め)・定数に関するスコープ(適用範囲)について紹介してきましたが、ここではVBAにおける構造体(ユーザー定義型)のスコープ(適用範囲)について触れていきたいと思います。
構造体(ユーザー定義型)をひと言で言えばオブジェクトの1つです。と言われても分かりにくいと思いますが、端的に言えばデータを格納できる箱の一種と考えると良いでしょう。変数との大きな違いは、変数は1つにつき1つの値のみですが、構造体(ユーザー定義型)は、データ型(整数型や文字列型など)が異なるものを複数個代入することができます。
構造体(ユーザー定義型)は、宣言セクションのみで宣言ができます。宣言方法は、Typeステートメントをつかって宣言します。
[Public|Private]Type 構造体名
要素名1
要素名2
要素名3
End Type
構造体(ユーザー定義型)は、以下の記事でも紹介していますので、宣言方法や使い方はそちらをご確認ください。
モジュールレベルの構造体(ユーザー定義型)のスコープ(適用範囲)
構造体(ユーザー定義型)は宣言セクションでのみ宣言できるため、宣言セクションで「Private」を使用することで構造体(ユーザー定義型)にモジュールレベルのスコープ(適用範囲)を指定することができます。
これにより、指定された構造体(ユーザー定義型)はモジュールの中だけであつかえるものとなります。
モジュールレベルの配列のスコープ(適用範囲)をあつかったサンプルマクロ
標準モジュールを2つ準備し、宣言セクションでモジュールレベルのスコープ(適用範囲)を指定した構造体(ユーザー定義型)が、宣言したモジュールで利用できることと、他のモジュールで利用できるかをサンプルマクロを実行して確認してみます。
こちらのモジュールでは、宣言セクションでユーザ定義型Aという名前のユーザー定義型(構造体)を「Private」で宣言しています。そして、同じモジュールのプロシージャである「ユーザー定義型に値の代入と出力1」のなかで値の代入と出力を実行してみます。
こちらのモジュールでは、宣言セクションでユーザー定義型(構造体)の宣言はおこなっていません。プロシージャ「ユーザー定義型に値の代入と出力2」のなかでユーザー定義型Aをつかうための宣言はしていますが、モジュール「ユーザー定義型のスコープ1」と同様に、「Private」で指定したユーザ定義型Aの利用ができるか値の代入と出力を試みます。
実行結果
キキさんのテストの結果
テスト実施日: 2010/02/02
60
55
72
85
28
コンパイルエラーが発生します。
以下の画像のように「ユーザ定義型は定義されていません。」のエラーが表示されます。

これにより、指定された構造体(ユーザー定義型)は、モジュールの中だけであつかえるものであることが確認できました。
パブリックレベルの構造体(ユーザー定義型)のスコープ(適用範囲)
構造体(ユーザー定義型)は、宣言セクションでのみ宣言できるため、宣言セクションで「Public」を使用することで構造体(ユーザー定義型)にパブリックレベルのスコープ(適用範囲)を指定することができます。
これにより、指定された構造体(ユーザー定義型)は、他のモジュールからもあつかえるものとなります。
パブリックレベルの配列のスコープ(適用範囲)をあつかったサンプルマクロ
モジュールレベルのときの検証と同じように、標準モジュールを2つ準備し、宣言セクションでパブリックレベルのスコープ(適用範囲)が指定された構造体(ユーザー定義型)が、いずれのモジュールからも利用ができることの確認をしてみます。
こちらのモジュールでは、宣言セクションでユーザー定義型Bという名前のユーザー定義型(構造体)を「Public」で宣言しています。そして、同じモジュールのプロシージャである「ユーザー定義型に値の代入と出力1_2」のなかで値の代入と出力を実行してみます。
こちらのモジュールでは、宣言セクションでユーザー定義型(構造体)の宣言はおこなっていません。プロシージャ「ユーザー定義型に値を代入と出力2_2」のなかでは、ユーザー定義型(構造体)をつかうための宣言はしていますが、先ほどのモジュール「ユーザー定義型のスコープ1_2」と同様に値の代入と出力を試みます。
実行結果
ソノさんのテストの結果
テスト実施日: 1997/02/02
69
75
70
50
35
このモジュールでパブリックレベルのユーザ定義型(構造体)を宣言していて、値を代入・出力するプロシージャも同じモジュールのなかにあるので、スコープ(適用範囲)の指定どおり、正常に値の出力ができていることがわかります。
コキリさんのテストの結果
テスト実施日: 1986/02/02
80
92
86
100
45
こちらのモジュールでは、ユーザ定義型(構造体)を宣言していませんが、「Public」で指定されたユーザ定義型(構造体)に対して、値を代入・出力することができていることから、スコープ(適用範囲)の指定どおり、宣言したモジュール以外からも、ユーザ定義型の利用ができていることがわかります。
ユーザ定義型(構造体)と使用宣言のための変数でスコープが異なる場合
ユーザ定義型は、モジュールの宣言セクションにおいて「Type」ステートメントで宣言するとお伝えしました。さらにスコープ(適用範囲)を指定するためには、「Public」または「Private」をつければ良いことになります。
それでは、以下のような宣言が行われた場合はどうなるでしょうか。
このモジュールの宣言セクションには、「ユーザ定義型A」と「ユーザ定義型B」という名前の2つのユーザ定義型(構造体)が宣言されています。さらに、それぞれを使用するための変数とて「UserA」と「UserB」も宣言しています。
注目しておきたい点は、ユーザ定義型(構造体)の宣言時と変数の宣言時のスコープ(適用範囲)が異なっている点です。スコープ(適用範囲)をパブリックレベルをモジュールレベルに、モジュールレベルをパブリックレベルにクロスさせたような状態にしています。(下記のイメージ図を参照)

具体的には、「ユーザ定義型A」はPrivateで宣言していますが、それを代入した変数である「UserA」はPublicで宣言しており、「ユーザ定義型B」はPublicで宣言していますが、変数の「UserB」はPrivateでの宣言にしています。
モジュールレベルであれ、パブリックレベルであれ、これらを宣言したモジュールでは利用可能であるため、宣言したモジュール以外のモジュールからの利用可否をまとめました。
モジュール1で宣言したオブジェクトと変数 | スコープ(適用範囲)の指定 | 宣言していないモジュール2からの利用 |
---|---|---|
ユーザ定義型A | Private | 不可 |
ユーザ定義型B | Public | 可能 |
UserA | ||
UserB | Private | 不可 |
変数「UserA」を他のモジュールから利用する場合は、値の代入や出力が直接できますが、「ユーザ定義型B」を他のモジュールから利用する場合は、通常のユーザ定義型(構造体)を利用するときと同様に宣言セクションもしくは、プロシージャでユーザ定義型(構造体)を使用するための変数の宣言文を書く必要があります。

スコープ(適用範囲)の結果をみると「ユーザ定義型」と「変数」は、別ものと考えて大丈夫そうだね。
エクセル・ワード・パワーポイントのオンライン学習
料金負担が安いのになんど見ても追加費用は不要!
安心の環境でしっかりとスキルをつけたいならPCHack
VBAのクラス変数のスコープ(適用範囲)
これまでは標準モジュールに宣言した変数、定数、ユーザ定義型(構造体)などのスコープ(適用範囲)について紹介してきました。ここでは、クラスモジュールで宣言した変数でスコープ(適用範囲)を指定する方法と変数の動作について紹介していきます。
クラスの変数のスコープ(適用範囲)の話題に入る前に、エクセルVBAには、標準モジュールやブック・シート・フォームモジュールの他に、クラスモジュールがあります。クラスモジュールの作り方や使い方についてはここで詳しくは書きませんが、クラスモジュールも、他のモジュールと同様にプロシージャを書くことや、変数の宣言ができ、スコープ(適用範囲)を指定することができます。
クラスモジュールの宣言セクションで宣言した、パブリックやモジュールレベルの変数のことを、クラスのプロパティと呼びます。また、クラスモジュールに書いたSubプロシージャや、Functionプロシージャのことをメソッドと呼びますが、メソッドでも標準モジュールと同じように変数の宣言ができます。
クラスのなかで宣言した変数も、標準モジュールと同じく、指定したスコープ(適用範囲)の種類によっては、外部から値の代入や出力ができます。しかし、大規模で複雑なマクロでは、どこからでも変数の値を書きかえられてしまうことは、システム開発においてマクロ全体のリスクになると考えられるため、スコープ(適用範囲)は必要最低限としておくといった考え方があります。
エクセルVBAでは、原則としてこの方針がありながらも、隠された変数(プロパティ)の値を設定したり、取得するための専用口としてプロパティプロシージャと呼ばれるものを使うことがありますので、これについてものちほど紹介します。
それでは、クラスにおけるスコープ(適用範囲)を指定した変数が、どのような動きになるかについてサンプルマクロを見ながら解説していきます。
クラスのメソッドで宣言した変数のスコープ(適用範囲)
こちらは標準モジュールのプロシージャで宣言した、プロシージャレベルの変数と同じです。クラスにおいてもプロシージャのなかで宣言した変数は、プロシージャのなかでのみ値の代入や出力ができます。
クラスのメソッドで宣言した変数をあつかったサンプルマクロ
こちらは、クラスモジュールを使うための処理とクラスに書いたプロシージャ(メソッド)を呼び出して、クラスのなかで宣言した変数に値の代入と出力をこころみます。なお、それぞれのメソッドを呼び出すときに引数を指定していますので、この値をクラスのなかの変数に代入します。
こちらはクラスモジュールに書いたコードです。プロシージャ(メソッド)を2つ準備していて、それぞれのプロシージャ名で「プロシージャレベルの変数に値の代入をする」Aと同名のBの2つを作成しています。
いずれのプロシージャ(メソッド)も処理している内容は、標準モジュール1から呼び出されたときに受け取った引数を変数名「クラスの変数」に代入し、イミディエイトウィンドウに変数の値を出力するといったシンプルなものです。
ただし、Aのプロシージャでは「クラスの変数」を宣言しており、Bでは変数の宣言をしていないという差分があります。
実行結果を確認してみます。
実行結果
チコリータ

こちらのプロシージャでは、上の画像のとおり「クラスの変数」が宣言されていないことから「変数が定義されていない」ことによるエラーとなりました。
この結果により、「クラスの変数」のスコープ(適用範囲)がプロシージャのなかに限定されていることが確認できました。
クラスでモジュールレベルの宣言をした変数(プロパティ)のスコープ(適用範囲)
今度は、クラスモジュールの宣言セクションで宣言した変数についてですが、標準モジュールと同じようにクラスモジュールで「Private」を使って宣言します。しかし、クラスモジュールはそれ単体ではなく、標準モジュールから呼び出して動かしますので、モジュールを2つつかうことになります。しかし、変数の宣言で指定したスコープ(適用範囲)は、モジュールレベルの変数(プロパティ)ですので、その変数が有効となる範囲は、変数を宣言したクラスモジュールとなります。
つまり、クラスモジュール内で変数を利用するのであれば問題なく動作しますが、スコープ(適用範囲)の外側にある、標準モジュールで変数を利用しようとするとエラーが発生します。
これについては、本章の冒頭でも少し触れましたが、クラスモジュールで宣言したモジュールレベルの変数(プロパティ)は、「プロパティプロシージャ」と呼ばれるものを使う方法で標準モジュールから利用ができます。
少し複雑な話になりましたが、ここで紹介するサンプルマクロの内容をまとめると以下になります。
- クラスモジュールで宣言した変数(プロパティ)をクラスモジュールで利用する
- クラスモジュールで宣言した変数(プロパティ)を標準モジュールから利用する
- クラスモジュールで宣言した変数(プロパティ)を標準モジュールからプロパティプロシージャを経由して利用する
上から順番にサンプルマクロを見ていきましょう。
クラスモジュールで宣言した変数(プロパティ)をあつかったサンプルマクロ
①クラスモジュールで宣言した変数(プロパティ)をクラスモジュールで利用する
まずは、宣言と処理が同じクラスモジュール内で完結しているものです。
言わずもがなですが、スコープ(適用範囲)がモジュールレベルの変数(プロパティ)を宣言しているクラスモジュールで、その変数をあつかうことはできます。
クラスモジュールで変数を宣言するため、標準モジュールでは変数の宣言はしていません。クラスを使うための宣言をして、クラスに書いた処理(C1_メソッド)を呼び出します。
クラスモジュールの宣言セクションで、変数名「Mポケモン_」を「Private」をつけてモジュールレベルで変数で宣言しています。標準モジュール(変数のスコープ_クラス)が実行されると、クラスを使うための処理がおこなわれたあと、クラス内のSubプロシージャである「C1_メソッド」が呼ばれます。
変数を宣言したモジュールと、値の代入、出力をするモジュールが同一であるため、正常動作として以下が出力されます。
実行結果
イミディエイトウィンドウに以下が表示されます。
バタフリー
引数に指定した値が変数に代入されていることが確認できました。
②クラスモジュールで宣言した変数(プロパティ)を標準モジュールから利用する
続いて、クラスモジュールで変数を宣言し、標準モジュール側で変数に値の代入と出力を実行しているマクロです。クラスモジュールで宣言した変数のスコープ(適用範囲)は、モジュールレベルであるため、標準モジュールから変数を見ることができず、値の代入や出力ができません。
そのため、マクロを実行するとエラーが発生します。
実行結果
コンパイルエラーが発生します。
下の画像のように「メソッドまたはデータ メンバーが見つかりません。」のエラーメッセージが表示されます。

クラスモジュールで宣言した変数(プロパティ)は、標準モジュールからは見えないためクラスモジュールのメンバである変数「Mポケモン_」が見つからない旨のメッセージとなります。
③クラスモジュールで宣言した変数(プロパティ)を標準モジュールからプロパティプロシージャを経由して利用する
さいごに、クラスモジュールで変数を宣言し、プロパティプロシージャを経由して標準モジュール側で変数に値の代入と出力を実行しているマクロです。クラスモジュールで宣言した変数のスコープ(適用範囲)は、モジュールレベルであるため、標準モジュールから変数を見ることができませんが、同じモジュールに属するプロパティプロシージャを一度経由することで値の代入や出力が実行できるようになります。このように外部からのアクセスできないスコープ(適用範囲)の変数に、特別な窓口を設けて変数(プロパティ)に値を設定するプロシージャをセッター、変数の値を取得するプロシージャをゲッターと呼びます。
セッターやゲッターを経由する処理のイメージは以下のとおりです。

それでは、セッターとゲッターを使ったサンプルマクロを見ていきましょう。
標準モジュールでは、変数の宣言はしていません。クラスを使うための処理を実行したあとで、プロパティプロシージャのセッターを呼び出しています。なお、セッターを呼び出すときに引数として代入したい値として”タッツー”を渡しています。そして最後にイミディエイトウィンドウにゲッターから受け取った値を出力する動作です。
クラスモジュールの宣言セクションで変数名「Mポケモン_」を宣言しています。その他にプロパティプロシージャのセッターとゲッターを書いています。セッターとゲッターはペアにすること、プロシージャ名を同じにします。
●Property Let ポケモン名(ByVal Val As String)
プロパティプロシージャのセッターです。サンプルマクロでは、標準モジュールから呼び出されたときに引数として”タッツー”がValに代入されています。受け取った値を変数の「Mポケモン_」に代入する処理をします。
なお、サンプルマクロでは変数であつかうデータが値であるため、プロシージャ名を「Property Let ポケモン名(ByVal Val As String)」としていますが、変数であつかうものがオブジェクトである場合は、「Property Let 〇〇〇」ではなく、「Property Set 〇〇〇」にする必要があります。
●Property Get ポケモン名() As String
プロパティプロシージャのゲッターです。サンプルマクロでは、標準モジュールから呼び出されると変数の「Mポケモン_」に入った値を戻り値としてポケモン名に代入する処理をします。
実行結果は以下のとおりです。
実行結果
イミディエイトウィンドウに以下が表示されます。
タッツー
このようにクラスモジュールで宣言したモジュールレベルの変数(プロパティ)は、プロパティプロシージャのセッターやゲッターを経由することで利用ができます。
クラスでパブリックレベルの宣言をした変数(プロパティ)のスコープ(適用範囲)
クラスモジュールの宣言セクションで「Public」ステートメントをつかって宣言します。
パブリックレベルの変数は、グローバル変数と呼ばれるものとなり、宣言をしたモジュール以外のモジュールからも値の代入や出力ができます。なお、パブリックレベルの変数の有効期限は、クラスモジュールを呼び出したモジュールの処理が完了するまでです。
それでは、クラスモジュールで宣言したパブリックレベルの変数に、標準モジュールから値の代入と出力を実行するマクロを見てみます。
クラスモジュールの宣言したパブリックレベルの変数のサンプルマクロ
同じモジュールで宣言した変数であっても、「Public」ステートメントをつかって宣言しているものは標準モジュールから値の代入や出力ができます。
以下のサンプルマクロでは、2つの標準モジュールと変数を宣言するクラスモジュールの3つを準備しています。それぞれの標準モジュールからクラスモジュールで宣言した変数に値を代入・出力してみます。
こちらの標準モジュールでは、2つのプロシージャを作成していて、それぞれのプロシージャからクラスモジュール(ポケモンクラス)で宣言したパブリックレベルの変数に対して値の代入と出力をするマクロになります。
サンプルマクロの「クラス変数に値を代入して出力するA」では、「クラス00」と「クラス01」という名前のオブジェクトを2つ作成して値を代入・出力しています。また、同じモジュールにある別の「クラス変数に値を代入して出力するB」では、「クラス02」というオブジェクトを宣言して値の代入と出力をしています。
もうひとつの標準モジュールになります。こちらもクラスモジュール(ポケモンクラス)で宣言したパブリックレベルの変数に対して値の代入と出力するマクロになります。こちらでは「クラス03」というオブジェクトに構成する要素として値を渡しています。
こちらがクラスモジュールになります。宣言セクションで「Public」ステートメントをつかって3つの変数(プロパティ)を宣言しています。
実行結果
イミディエイトウィンドウに以下を表示します。こちらは標準モジュール(クラス変数に値を代入して出力するA)の実行結果です。
先頭行の「アチャモ」から、6行目の「6.5」までが「クラス変数に値を代入して出力するA」の実行結果でそれ以降の行は「クラス変数に値を代入して出力するB」の結果となります。結果からいずれのプロシージャからもクラスで宣言した変数に値の代入と出力が出来ています。
アチャモ
0.4
2.5
イーブイ
0.3
6.5
フシギダネ
0.7
6.9
つづいて、標準モジュール(クラス変数に値を代入して出力するB)の実行結果です。イミディエイトウィンドウに以下を表示します。
ポッチャマ
0.4
5.2
異なるモジュールで宣言した変数であっても、Publicステートメントをつかって宣言しているため、標準モジュールから値の代入や出力ができます。
実行結果からもわかるとおり、クラスモジュールでも「Public」ステートメントをつかって宣言した変数は、パブリックレベルの変数(グローバル変数)となります。これらの変数(プロパティ)は、標準モジュールから値の代入や出力ができます。
サンプルマクロでも、標準モジュールAにある2つのプロシージャから変数の利用ができていることがわかります。また、下のイメージ図のように別の標準モジュールにあるプロシージャからでも問題なく変数(プロパティ)が利用できます。

VBAの変数におけるスコープ(適用範囲)まとめ
この記事では、標準モジュールやクラスモジュールで宣言した変数や定数で、スコープ(適用範囲)を指定したときに、他のモジュールやプロシージャから利用する方法を紹介しました。
スコープ(適用範囲)を意識してマクロを作れるようになると、大きな規模のマクロでも処理を分けて管理することができるため、可読性の向上とメンテナンスのしやすさなどの効果があります。
それでは、この記事で紹介した内容をまとめていきます。
- 変数や定数は宣言方法によってスコープ(適用範囲)が指定できる
宣言方法によってスコープ(適用範囲)が異なり、共有できる範囲が変わってくる - スコープ(適用範囲)は3つの種類がある
- プロシージャレベル
SubやFunctionなどのプロシージャのなかで「Dim」をつかって宣言します。宣言したプロシージャのなかで有効な変数です。 - モジュールレベル
モジュールの宣言セクションで「Private」をつかって宣言します。同じモジュールのプロシージャから利用ができるものとなり、宣言したモジュールのなかで有効な変数です。 - パブリックレベル
モジュールの宣言セクションで「Public」をつかって宣言します。プロジェクト全体で利用ができるものとなり、ほかのモジュールからでも値の代入や出力ができる変数です。
- プロシージャレベル
- モジュールやパブリックレベルのスコープ(適用範囲)をあつかうときの注意点
- 変数名の名づけかた
- 共有している変数をほかのプロシージャで値を書きかえると意図しない動作が発生するリスクがある
- 共有している変数を宣言したモジュールがわかるようにしておく
- 共有している変数が影響するプロシージャをわかるようにしておく
- 変数と同じく定数もスコープ(適用範囲)の指定ができる
- 定数は宣言と同時に値を設定し、そのあとで値の変更はできない
- 定数であつかえるデータ型は、変数と比較すると限られている
- 変数の有効期限について
- スコープ(適用範囲)によって変数の有効期限も変わる
- プロシージャレベルの変数の有効期限は「Static」をつかえばブックを閉じるまで有効になる
- 変数の有効期限を完全に信用するのではなく、値を長期的に保存する場合はワークシートのセルに書き出すなどの方法を検討する
- 配列もスコープ(適用範囲)が指定できる
- ユーザ定義型(構造体)はモジュールレベルとパブリックレベルでスコープ(適用範囲)が指定できる
- クラスモジュールで宣言した変数にもスコープ(適用範囲)で指定できる
- 一般的には小さなスコープ(適用範囲)で指定することが望ましいとされている
- モジュールレベルの変数はプロパティプロシージャを経由することで値の代入・出力ができる

変数のスコープ(適用範囲)を理解すると今よりもっと便利に変数が使えるよ。
今回はここまで。
コダマのもりブログはにほんブログ村に登録しています。
ブログの記事が役に立ったと感じて頂けたら、フォローお願いいたします。
コメント