はじめに
エクセルVBAでマクロの作成をしていると、変数をつかうことが必須となってきます。マクロの作成において、変数を自在に扱えるようになればマクロでできることが大幅に広がってきます。むしろ実務的なレベルでの自動化などは変数を利用することが必須であると言えます。
この記事では、エクセルVBAの変数が扱えるようになった人向けに、変数のスコープ(有効範囲)と有効期限(代入された値やオブジェクトが保持される期間)について解説しています。
まず、変数のスコープ(有効範囲)とは、ひとことで言えばその変数がどの範囲で利用できるかを指定したものとなります。マクロの処理をそれぞれでパート(部品)化する上で知っておきたい内容であり、大規模で複雑なマクロであればあるほど、ひとつのプロシージャに大量のコードを書きこむ方法が絶対にダメであるとは言えませんが、それぞれの役割をもった処理がまとめて書かれていると、コード量も多くなるだけでなく、問題発生時の原因の抽出が難しくなることや、プログラム全体を把握しづらいものとなります。
そこで、それぞれの処理ごとにプロシージャや、モジュールの単位でプログラムをまとめていくことが大切であり、可読性を良くすることや、メンテナンスのしやすくすることは、マクロ全体の質の向上につながります。
また、このようなマクロを構築していく上では、それぞれのモジュールやプロシージャで共有したい値やデータがでてきます。例えば、あるワークシートを変数に代入する処理を何度も繰り返し書く必要はありません。目的のシートを共有できる変数に代入しておけばほかのモジュールやプロシージャからでもあつかうことができます。
一度、ワークシートを代入した変数を、ほかのモジュールであつかう必要も出てくるため、宣言した変数のスコープ(適用範囲)を意識する必要があります。スコープ(適用範囲)を指定して値やデータを共有することは、便利さと引きかえにマクロの実行エラーや、意図しない動作の発生を招くリスクも含まれるため、これらの事象を予防するためにも、それぞれの変数がもつスコープ(適用範囲)を理解したうえで活用することが求められます。
変数のスコープ(適用範囲)は大きく3つに分類されます。他のモジュールからもあつかえるスコープ(適用範囲)の変数をグローバル変数といい、これがもっともスコープ(適用範囲)が広いものです。次に同じモジュールの他のプロシージャからもあつかえるスコープ(適用範囲)のモジュールレベルの変数があり、さいごにプロシージャのなかだけでのみ利用する変数があり、こちらがもっともスコープ(適用範囲)が狭いものです。
この記事では、VBAの変数がもつスコープ(適用範囲)の指定方法と指定したときの動作について、または変数や定数の有効期限について紹介していきます。これらの内容について記事を読んだ人の理解が少しでも深まれば幸いです。
この記事の内容
ここでは、エクセルVBAであつかう変数のスコープ(適用範囲)について解説しています。エクセルVBAの変数のスコープや有効期限について以下の内容について知ることができます。
VBAの変数におけるスコープ(適用範囲)
まずは、それぞれの変数のスコープ(適用範囲)について紹介します。
プロシージャレベル変数のスコープ(適用範囲)
プロシージャの中で宣言する変数です。
Subや、FunctionからEnd SubやEnd Functionのなかで、「Dim」ステートメントをつけて宣言しているものがこちらに当たります。こちらの変数は、プロシージャレベルの変数と呼ばれ、変数を宣言したプロシージャ以外からの値の代入や、参照はできません。
なお、プロシージャレベルの変数は、プロシージャの処理が完了した時点で変数の値はリセット(初期化)されます。
プロシージャレベルの変数をあつかったサンプルマクロ
Option Explicit Sub プロシージャレベルの変数() '① 'プロシージャレベル変数"P"を宣言して100を代入する Dim P As Long: P = 100 Debug.Print "税込価格: "; P * 1.1 & " 円です。" End Sub Sub プロシージャレベルの変数にアクセス() '② Debug.Print "税込価格: "; P * 1.1 & " 円です。" End Sub
こちらのサンプルマクロでは、プロシージャを2つ作成しており「プロシージャレベルの変数()」を①、「プロシージャレベルの変数にアクセス()」を②としています。
①では、プロシージャレベル変数として、変数Pを宣言しています。また、①、②のいずれも、Debug.Printで変数Pの値を出力するコードを書いていますので実行してみます。
実行結果
①「プロシージャレベルの変数()」を実行すると以下がイミディエイトウィンドウに表示されます。
税込価格: 110 円です。
②「プロシージャレベルの変数にアクセス()」を実行すると「変数が定義されていない」エラーが発生します。
この結果から、変数Pを宣言していないプロシージャの②から、変数Pの値を参照することができないことがわかります。
モジュールレベル変数のスコープ(適用範囲)
プロシージャレベルの変数と異なり、モジュールの宣言セクションで宣言をする変数です。
宣言セクションで、Dimステートメントや、Privateステートメントをつかって宣言することでモジュールレベルの変数となります。
プロシージャレベルの変数と異なる点として、同じモジュールに書かれた他のプロシージャからでも値の代入や参照ができます。なお、モジュールレベルの変数の有効期限は、宣言したモジュールの処理が完了するまでです。
モジュールレベルの変数をあつかったサンプルマクロ
Option Explicit Dim M1 As Long 'Dimステートメントで宣言 Private M2 As Long 'Privateステートメントで宣言 Sub モジュールレベルの変数A() '① M1 = 1000 'Dimで宣言した変数に値を代入する M2 = 10000 'Privateで宣言した変数に値を代入する Debug.Print "税込価格: "; M1 * 1.1 & " 円です。" Debug.Print "税込価格: "; M2 * 1.1 & " 円です。" Call モジュールレベルの変数B '他プロシージャ②を呼び出す End Sub Sub モジュールレベルの変数B() '② M1 = M1 / 2 'Dimで宣言した変数に値を更新する M2 = M2 / 2 'Privateで宣言した変数に値を更新する Debug.Print "税込価格: "; M1 * 1.1 & " 円です。" Debug.Print "税込価格: "; M2 * 1.1 & " 円です。" End Sub
こちらのサンプルマクロでは、標準モジュールの宣言セクションで「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)」の宣言セクションで宣言したパブリックレベルの変数に、値の代入や出力を実行してみます。
以下に、それぞれのモジュールに書いたプロシージャと動作について解説します。
Option Explicit Public G As String 'パブリックレベル変数を宣言 Sub パブリックレベルの変数A() '① G = G &"株式会社オブジェクト" 'Publicで宣言した変数に値を代入する Debug.Print Mid(G, InStr(G, "社") + 1) '"社"の文字よりも右側だけ抽出する Call パブリックレベルの変数B '他プロシージャ②を呼び出す End Sub Sub パブリックレベルの変数B() '② G = G & " Plus One" 'Publicで宣言した変数に値を代入する Debug.Print Mid(G, InStr(G, "社") + 1) '"社"の文字よりも右側だけ抽出する Call 変数のスコープ2_2.パブリックレベルの変数C '他モジュールのプロシージャ③を呼び出す End Sub
上記のモジュールには、宣言セクションでPublicステートメントをつけて変数「G」を宣言しています。なお、今回はデータ型を文字列(String)型にしていますので、文字列を代入・参照していくマクロとなります。
また、こちらのモジュールは、2つのプロシージャを作成しています。コメントでそれぞれに①と②という番号づけしていますので、以降の説明にはこちらの番号を利用したいと思います。
まず、①のプロシージャを実行すると、変数「G」に「株式会社オブジェクト」も文字列を代入します。その直ぐ下の行において、変数「G」にイミディエイトウィンドウに出力する処理を行います。なお、ここでは社名である”オブジェクト”の部分のみを取り出す文字列操作処理を想定しており、Mid関数や、InStr関数をつかって出力する内容を操作しています。
続いて、Callステートメントをつかって、②のプロシージャを呼び出していますが、変数「G」を引数には指定していません。プロシージャ②のなかで、変数「G」に先ほど①のプロシージャで代入された値を更新し、①と同様にイミディエイトウィンドウに出力します。
さらに、Callステートメントをつかって、他のモジュールに書かれたプロシージャ(パブリックレベルの変数C)を呼び出す処理をします。
Option Explicit Sub パブリックレベルの変数C() '③ G = G & " ぷらす 2" 'Publicで宣言した変数に値を代入する Debug.Print Mid(G, InStr(G, "社") + 1) '"社"の文字よりも右側だけ抽出する End Sub
パブリックレベルの変数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」を使った繰り返し処理の書きかたは、過去の記事であつかっています。
以下のリンクより読むことができますので合わせてご覧ください。
パブリックレベルの変数は宣言したモジュールをわかるようにする
パブリックレベルの変数は、他のモジュール内のプロシージャによる影響をうけてしまう恐れがあるため、エラーが発生した場合は処理をさかのぼって、どこが原因でエラーになる処理が実行されているかを検証する必要がでてきます。
この作業を容易でスムーズにするためにも、パブリック変数に値を代入する、出力するなどの処理を実行する場合に、その変数を宣言したモジュールがわかるようにコードを書くことや、コメントに残すことが望ましいと言えます。
具体的には、以下のマクロにおける下線部分のようにコメントアウトをすることや、コード上でモジュール名を省略することが可能な場合であっても、敢えて書き残すことでその変数がどのモジュールで宣言されたのかが、ひと目でわかるようにする方法があります。
Option Explicit Public Sモジュール1で宣言 As Date
Option Explicit Sub Sモジュール2のプロシージャ() '①パブリックレベルの変数を宣言したモジュールがわかるようにコメントする Sモジュール1で宣言 = Date 'TESTモジュール1で宣言した変数に今日の日付を代入する Debug.Print Sモジュール1で宣言 '②どのモジュールで宣言したかをコードにも書き残す Sモジュール1.Sモジュール1で宣言 = DateAdd("d", 1, Date) '宣言したモジュール(Sモジュール1)を明記する Debug.Print Sモジュール1.Sモジュール1で宣言 End Sub
補足として、②のようにVBAのコードにモジュール(オブジェクト)名まで書くと、コードが長くなる可能性はあります。
ただ、コード量をなるべく減らし、スッキリさせて可読性を上げる行為は、マクロ全体を把握しやすくし、エラーの発生を予防する、機能拡大などのアップデートを容易にするなどの目的のための手段です。このケースの場合などで、モジュール名を敢えて書き残すことで「プログラムを見やすくする、理解を促す」という同じ目的に従ったものであれば誤りではなく、手段の選択だと言えるはずです。
コード量を減らすことが目的ではないということだね。
パブリックレベルの変数は使用しているプロシージャをわかるようにする
前項と同じく、パブリックレベルの変数をあつかって処理をしているプロシージャがわかるようにコメントを残すことで、意図しない動作の予防や、エラー発生時の検証作業、機能の拡大などのアップデートをしやすくする効果があるため、パブリックレベルの変数をあつかうプロシージャがわかるようにコメントを残すことも望ましいと言えます。
コメントの書きかたは自由ですが、わかりやすくするためにサンプルマクロでは、下線部のようにモジュール名(プロシージャ名)で利用とコメントアウトしています。
Option Explicit
'Sモジュール2(Sモジュール2のプロシージャ)で利用
Public Sモジュール1で宣言 As Date
Option Explicit Sub Sモジュール2のプロシージャ() '①パブリックレベルの変数を宣言したモジュールがわかるようにコメントする Sモジュール1で宣言 = Date 'TESTモジュール1で宣言した変数に今日の日付を代入する Debug.Print Sモジュール1で宣言 '②どのモジュールで宣言したかをコードにも書き残す Sモジュール1.Sモジュール1で宣言 = DateAdd("d", 1, Date) '宣言したモジュール(Sモジュール1)を明記する Debug.Print Sモジュール1.Sモジュール1で宣言 End Sub
なぜ、膨大な事務作業でも定時で退社できるのか。
実務をプロから学べる「ユースフル」の動画は永年見放題。Q&A機能で分からないを放置しないから安心。
詳しくは以下のリンクをクリック
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の定数の使いどころ
定数は、余程のことがない限り変わらない値をあつかう場合に利用すると良いでしょう。
以下に定数をあつかったサンプルマクロを作りましたので、参考にしてください。
定数をつかったサンプルマクロ
マクロの動作を分かりやすくするために、簡単な表(なんとかひょう)を作成し、薄い色のついたセルの部分を算出した結果を出力してみます。
Option Explicit Sub 計算するプロシージャ() Const Duty As Double = 0.1 '税率用定数の宣言と代入をする Dim i As Long: i = 5 '繰り返し用変数の宣言と代入をする 'Withでコードをまとめる With ThisWorkbook.Sheets("Const使用例") Do Until .Cells(i, 2) = "" .Cells(i, 6) = Format(.Cells(i, 5) * Duty, "#,##0") '各行に税額を出力 .Cells(i, 7) = Format(.Cells(i, 5) + .Cells(i, 5) * Duty, "#,##0") '各行に税込価格を出力 i = i + 1 Loop '合計行まで行を行数を送る処理 Do While .Cells(i, 2) = "" i = i + 1 Loop '合計行の販売価格・税額・税込価格の合計値を出力 .Cells(i, 5) = Application.WorksheetFunction.Sum(.Range(.Cells(5, 5), .Cells(i - 1, 5))) '販売価格合計 .Cells(i, 6) = Application.WorksheetFunction.Sum(.Range(.Cells(5, 6), .Cells(i - 1, 6))) '税額合計 .Cells(i, 7) = Application.WorksheetFunction.Sum(.Range(.Cells(5, 7), .Cells(i - 1, 7))) '税込販売価格合計 End With End Sub
こちらのマクロでは、定数はConstステートメントをつかって「Duty」という名前で宣言しています。また、データの型はDouble(小数点)型とし、宣言と同時に0.1を代入しています。
このように定数で指定しておくことで、たとえ将来的に税率が変わったとしても、定数に代入する値だけを更新すればマクロのアップデートができるため、複雑なコードが書きこまれた部分を触ることがないといったメリットがあります。
それでは、マクロを実行したあとの表の画像を見ていきます。
実行結果
各行の販売価格(税込)と販売価格、税額、販売価格(税込)の合計値を出力しました。
税率の部分は変数でも良いのでは?と思われるかもしれませんが、もちろん変数でも問題なく動作します。また、変数をつかった同じようなコードであった場合のアップデートにかかる手間も全く変わらないですが、定数をつかうことの利点は”一度代入した値は更新できない”ことであり、他のプロシージャからの処理の影響をうけないところだと言えます。この点がマクロに定数をつかう理由として、変数と区別ができる最大のポイントだと言えます。
さて、前置きが長くなってしまいましたが、次項からは定数のスコープについて解説していきます。
定数のスコープ(適用範囲)の種類
それでは、定数のスコープ(適用範囲)の種類ですが、変数と同様に以下のとおりとなります。
- プロシージャレベルのスコープ(適用範囲)
- モジュールレベルのスコープ(適用範囲)
- パブリックレベルのスコープ(適用範囲)
サンプルマクロとともに、それぞれを詳しくみていきましょう。
プロシージャレベルのスコープ(適用範囲)の定数
プロシージャ内で宣言したものは、こちらになります。
プロシージャ内でのみ定数の値の利用が可能であり、他のプロシージャやモジュールからは値の利用ができません。
プロシージャレベルのスコープ(適用範囲)の定数をあつかったサンプルマクロ
Option Explicit Sub プロシージャレベルの定数() '① 'プロシージャレベル定数"PC"を宣言して0.1を代入する '※定数名のPCは、procedureの「P」とConstの「C」の頭文字です。 Const PC As Double = 0.1 'インプットボックスで100が入力されたと想定 Dim Price As Long: Price = Application.InputBox("価格を入力してください。", "価格入力") Debug.Print "税込価格: \"; Price + Price * PC; " 円です。" End Sub Sub プロシージャレベルの定数にアクセス() '②※定数PCが定義されていないため、変数が定義されていないエラーとなる 'インプットボックスで100が入力されたと想定 Dim Price As Long: Price = Application.InputBox("価格を入力してください。", "価格入力") 'プロシージャレベル定数"PC"の値を利用する Debug.Print "税込価格: \"; Price + Price * PC; " 円です。" End Sub
プロシージャ①を実行すると、価格を入力するインプットボックスを表示します。ここでは、100 を入力した結果を確認してみます。次にプロシージャ②ですが、こちらはプロシージャレベルの定数”PC”を異なるプロシージャから利用しようとしているため、「変数が定義されていない」エラーが発生します。
実行結果
プロシージャ①の実行結果
税込価格: ¥ 110 円です。
プロシージャ②の実行結果
定数名「PC」は、プロシージャレベルの定数であるため、宣言したプロシージャ①では利用が可能であり、他のプロシージャである②からでは、値の利用ができないことが確認できていることから、定数「PC」のスコープ(適用範囲)は宣言したとおり、宣言したプロシージャのみであることが確認できました。
モジュールレベルのスコープ(適用範囲)の定数
宣言したモジュール以外から定数の値が利用できます。各モジュールの宣言セクションにて「Private」ステートメントをつけることで宣言できます。また、「Public」や「Private」ステートメントを省略した場合は、モジュールレベル(Privateで宣言したものと同様)の定数となります。
モジュールレベルのスコープ(適用範囲)の定数をあつかったサンプルマクロ
Option Explicit '定数名のMCは、moduleの「M」とConstの「C」の頭文字です。 Private Const MC As String = "これはプライベート定数です。" Sub パブリック_モジュールレベルの定数にアクセス正常() '①定数MCの値を出力する Debug.Print MC 'これはプライベート定数です。 End Sub Sub モジュールレベルの定数にアクセス不正() '②※定数MCの値は更新できないためエラーとなる Debug.Print MC MC = "MCの文字列を書き換えました。" '定数には値を代入できませんのエラーメッセージを表示する End Sub
プロシージャ①を実行すると、定数「MC」に代入された文字列”これはプライベート定数です。”を出力します。次にプロシージャ②では、プロシージャレベルの定数「MC」の値を更新しようとしていますが、こちらは「定数には値を代入できません」のエラーが発生します。
実行結果
プロシージャ①の実行結果
これはプライベート定数です。
プロシージャ②の実行結果
定数名「MC」は、モジュールレベルの定数であるためスコープ(適用範囲)から言えば、プロシージャ①だけでなく、プロシージャ②からも利用が可能です。しかし、プロシージャ②では、定数「MC」に代入された値を更新するコードを書いているためにエラーが発生する結果となっています。
なお、プロシージャ②の定数「MC」の値を更新するコード部分である「MC = “MCの文字列を書き換えました。” 」をコメントアウトすると、実行時エラーは発生せずにプロシージャ①と全く同じ結果となります。
パブリックレベルのスコープ(適用範囲)の定数
宣言したモジュール以外から定数の値が利用できます。標準モジュールの宣言セクションにて「Public」ステートメントをつけることで宣言できます。ただし、パブリックレベルの定数は標準モジュール以外では宣言できません。
パブリックレベルのスコープ(適用範囲)の定数をあつかったサンプルマクロ
Option Explicit '定数名のGCは、globalの「M」とConstの「C」の頭文字です。 Public Const GC As String = "これはパブリック定数です。" Sub パブリック_モジュールレベルの定数にアクセス正常() '①定数GCの値を出力する Debug.Print GC 'これはパブリック定数です。 End Sub Sub パブリックレベルの定数にアクセス不正() '②※定数GCの値は更新できないためエラーとなる Debug.Print GC GC = "GCの文字列を書き換えました。" '定数には値を代入できませんのエラーメッセージを表示する End Sub
Option Explicit Sub パブリックレベルの定数にアクセス正常() '③定数GCの値を出力する Debug.Print GC 'これはパブリック定数です。 End Sub
定数「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 | ブック(ファイル)を閉じる |