変数、定数、プロシージャのスコープについて実際のコーディング例、動画を使ってその有効範囲、利用目的を理解しよう。
目次
VBAのスコープ宣言の方法
変数や定数、プロシージャ を定義する際これらを参照できる範囲を スコープ宣言により指定することができます。
VBA ではこの スコープ 宣言によリ別の モジュール、プロシージャから変数や定数、またはプロシージャを使用できるかを制限することができます。
実は
の中で登場した
Dim 変数名 As 型指定文字
はプロシージャの中でのみ有効なローカル変数を宣言する方法なのですが、スコープの種類には
- プロシージャの中でのみ有効なローカルレベル
- プライベートな モジュールレベル
- パブリックなモジュールレベル
というの 3 つのレベルがあり、それぞれの利用範囲を次のような宣言の予約語を使って宣言します。
宣言予約語 | 意味・利用範囲 |
---|---|
Dim Const |
ローカル変数 をプロシージャの中で宣言するときに使います。 Dimで宣言されたローカル変数、Const で宣言されたローカル定数のメモリはプロシージャが開始した際に確保され、プロシージャが終了すると解放されるため他のプロシージャから参照できません。 |
Private |
モジュールの中に含まれる全てのプロシージャで参照可能な変数、定数、プロシージャを宣言するとき、モジュールの中の全てのプロシージャ宣言の前に単独もしくは定数、プロシージャを宣言する予約語の前に付加して宣言するときに使います。 単一または複数のプロシージャを宣言しているモジュール内のすべてのプロシージャの中で参照できます。また逆に他のモジュールからは参照できません。 Privateで宣言された Private 変数、定数はプロシージャの開始、終了にかかわらずメモリが保持されます。 |
Public |
プロジェクト(=ファイル)の中に含まれる全てのモジュールの中に含まれる全てのプロシージャで参照可能な変数、定数、プロシージャを宣言するとき、その変数もしくはプロシージャを収容するモジュールの中の全てのプロシージャ宣言の前に、単独もしくは定数、プロシージャを宣言する予約語の前に付加して宣言するときに使います。 単一または複数のモジュールが定義され、それぞれのモジュール内に複数のプロシージャがある場合、それらのすべてのプロシージャの中で参照できます。 Publicで宣言された Public 変数はプロシージャの開始、終了にかかわらずメモリが確保されます。 |
モジュールとは何か
ところでモジュールって何でしょうか?
プログラムの規模が小さいとき、プログラムを自分だけで開発しているときは必要性は殆ど感じませんが
- プログラムを大きな機能毎に分割したいとき
- プログラムを複数の担当者で共同開発したいとき
- 複数のプロジェクトで使用する共通な関数等をあるファイルにまとめ、他のファイルがその関数を参照したいとき
- GitHUB等のインターネット上から必要なコーディングを自分のプログラムに組み込みたいとき
それぞれのかたまりをモジュールという単位のかたまりにまとめて保存します。これがモジュールです。
モジュールを分割しておくと便利なので必要に応じて使用して下さいね。
それでは理解を助ける為に
Access の VBE 画面で記述された
コーディング例を使って具体的に確認してみましょう。
変数のスコープの違いを確認しよう
この画像は Access で VBA のコーディングをするときに使う VBE(Visual Basic エディタ)です。
Excel 、Word、Outlook、PowerPoint 等、他の Office アプリケーションの VBE も VBE 左側のプロジェクトウインドウで現れているオブジェクトの種類に少し差があるだけで、メニュー構成、利用可能な画面、機能、標準モジュール配下の構成を含めて同じになっています。
このあたりは自分がよく使用するアプリケーションで
実際にVBEを開いて確認してみてくださいね。
またこの記事内のコーディングをあなたの環境で実際にコピーして動かして理解を深めましょう。
この画面の左側のプロジェクトウインドウの中で標準モジュール配下は
- 標準モジュール
- Module1
- Module2
のようになってますよね。
この Module1、Module2 がモジュールです。
そして画面の右側に2つ領域があって、タイトル部が
- Databese1-Module1(コード)
- Database1-Module2(コード)
となっていますよね。
これはそれぞれのコーディング領域の名前なのですが、そこにVBAのコーディングが記述されているということです。
話を元に戻しましょう。
この記事ではではそれらの領域に以下のようにVBAのコーディングを記述しています。
Database1-Module1(コード)
Option Compare Database
Public varPublic As Integer
Private varPrivate As Integer
Sub sample1()
Dim varDim As Integer
varDim = 1
varPrivate = 1
varPublic = 1
MsgBox "varDim = " & varDim & vbCrLf & "varPrivate = " & varPrivate & vbCrLf & "varPublic = " & varPublic
End Sub
Sub sample2()
Dim varDim As Integer
varDim = 2
MsgBox "varDim = " & varDim & vbCrLf & "varPrivate = " & varPrivate & vbCrLf & "varPublic = " & varPublic
End Sub
Database1-Module2(コード)
Option Compare Database
Sub sample3()
Dim varDim As Integer
varDim = 3
MsgBox "varDim = " & varDim & vbCrLf & "varPrivate = " & varPrivate & vbCrLf & "varPublic = " & varPublic
End Sub
それでは変数のそれぞれの宣言における特徴を見て行きましょう。
Public 変数の特徴
- Public 変数のメモリ領域はこのプロジェクト(ファイル)が起動された際に Module1 内に確保され、プロジェクト終了までこのメモリ領域が保持されます
- 例えばこの例の Public 変数 varPublic にはこのプロジェクトに含まれる全てのモジュール(この例では Module1、Module2)に含まれる全てのプロシージャ(この例では Sample1、Sample2、Sample3) から読み書きが可能です
Private 変数の特徴
- Private 変数のメモリ領域はこのプロジェクト(ファイル)が起動された際に Module1 内に確保され、プロジェクト終了までこのメモリ領域が保持されます
- 例えばこの例の Public 変数 varPublic は Module1 に含まれる全てのプロシージャ(この例では Sample1、Sample2) からのみ読み書きが可能。逆に Module2 の Sample3 から参照することはできません
Module2 の Sample3 内の MsgBox 関数内使用されている varPrivate は
ローカル変数 varPrivate が Variant 型として暗黙的に宣言されていることに注意してくださいね
ローカル変数の特徴
- プロシージャ内で Dim で宣言されたローカル変数のメモリ領域は各プロシージャの起動時にそのプロシージャ内で確保され、そのプロシージャの終了とともに開放されます
- 例えばこの例ではプロシージャ内の個々のローカル変数 varDim はプロシージャ終了と共に解放されるため、他のプロシージャから参照することはできません
それでは以上を踏まえて、実際の動きを次の動画内のVBE 内のローカルウインドウを参照し、必要に応じて画面を止めながら確認しましょう。
見づらいときは画面をフルスクリーンにすることをお勧めします。
ローカルウインドウはVBEの中で利用している変数の値がリアルタイムで参照可能なツールでプロシージャをステップインモードで起動後、F8キーを押しながら1ステップ毎に実行するたびに変数の値が参照できる優れモノです。
|
定数のスコープの違いを確認しよう
同様に定数についても同様の確認をしてみましょう。
Database1-Module1(コード)
Option Compare Database
Public Const C_PUBLIC As Integer = 1
Private Const C_PRIVATE As Integer = 2
Sub sample1()
Const C_SUB As Integer = 3
Debug.Print C_PUBLIC, C_PRIVATE, C_SUB
End Sub
Sub sample2()
Debug.Print C_PUBLIC, C_PRIVATE, C_SUB
End Sub
Database1-Module2(コード)
Option Compare Database
Sub sample3()
Debug.Print C_PUBLIC, C_PRIVATE, C_SUB
End Sub
Public 定数の特徴
- Public 定数のメモリ領域はこのプロジェクト(ファイル)が起動された際に Module1 内に確保され、プロジェクト終了までこのメモリ領域が保持されます
- この例では Public 定数 C_PUBLIC はこのプロジェクトに含まれる全てのモジュール(この例では Module1、Module2)に含まれる全てのプロシージャ(この例では Sample1、Sample2、Sample3) から読み書きが可能です
Private 定数の特徴
- Private 定数のメモリ領域はこのプロジェクト(ファイル)が起動された際に Module1 内に確保され、プロジェクト終了までこのメモリ領域が保持されます
- この例では Public 定数 C_PRIVATE には Module1 に含まれる全てのプロシージャ(この例では Sample1、Sample2) からのみ読み書きが可能。逆に Module2 の Sample3 から参照することはできません
ローカル定数の特徴
- 個々のプロシージャの中で定義されたローカルな定数のメモリ領域は各プロシージャの起動時にそのプロシージャ内で確保され、そのプロシージャの終了とともに開放されます
- この例ではローカル変数 C_SUB はプロシージャ終了と共に解放されるため、他のプロシージャから参照することはできません
つまり
変数と定数のスコープ
は全く同じ性質を持っているんだね
プロシージャのスコープの違いを確認しよう
最後にプロシージャのスコープはどうなっているでしょうか?変数や定数と同じでしょうか?
ここでいうプロシージャには Subプロシージャ、Functionプロシージャ(関数)の両方を含みます。
プロシージャのスコープに関して確認するために、変数同様、以下のようなサンプルプログラムを作成して確認してみましょう。
Database1-Module1(コード)
具体的なコーディングの内容は以下の通りです。
Database1-Module1(コード)
Option Compare Database
Public Sub procPublic()
MsgBox "procPublic@Module1"
End Sub
Public Function functionPublic() As Integer
MsgBox "functionPublic@Module1"
functionPublic = 1
End Function
Private Sub procPrivate()
MsgBox "procPrivate@Module1"
End Sub
Private Function functionPrivate() As Integer
MsgBox "functionPrivate@Module1"
functionPrivate = 2
End Function
Sub procLocal1()
MsgBox "procLocal1@Module1"
End Sub
Function functionlocal() As Integer
MsgBox "functionlocal@Module1"
functionlocal = 3
End Function
Sub procLocal2()
Call procPublic
Call procPrivate
Call procLocal1
MsgBox "functionPublic: " & functionPublic()
MsgBox "functionPrivate: " & functionPrivate()
MsgBox "functionLocal: " & functionPrivate()
End Sub
Database1-Module2(コード)
Option Compare Database
Sub procLocal2()
Call procPublic
' Call procPrivate
Call procLocal1
MsgBox "functionPublic: " & functionPublic()
' MsgBox "functionPrivate: " & functionPrivate()
MsgBox "functionLocal: " & functionlocal()
End Sub
それではプロシージャのそれぞれの宣言における特徴を見て行きましょう。
Public プロシージャの特徴
- この例では Public プロシージャ procPublic, functionPublic はこのプロジェクトに含まれる全てのモジュール(この例では Module1、Module2)に含まれる全てのプロシージャ(この例では procLocal1, proclocal2 ) から呼び出しが可能です
Private プロシージャの特徴
- この例の Private プロシージャ procPrivate, functionPrivate は Module1 内のプロシージャ(この例では procLocal1) から参照できますが、Module2 内のプロシージャ(この例では procLocal2) から参照することはできません
ローカルプロシージャの特徴
- この例では ローカルプロシージャ procLocal1, functionLocal はこのプロジェクトに含まれる全てのモジュール(この例では Module1、Module2)に含まれる全てのプロシージャ(この例では procLocal1, proclocal2 ) から呼び出しが可能です
これをみてあれっと思いませんでしたか?
Private 宣言が Module をまたいだ参照ができないというのは変数と同じなのですが
・ローカル宣言された Proc、Function
・Public 宣言された Proc, Function
の両者は全く同じ参照条件となっています。Microsoft の公式ページによるとプロシージャはデフォルトがPublicとなっていて、必要に応じてPrivate でモジュール間の干渉をおさえるという考え方となっています。
まとめ
VBAの変数、定数、プロシージャではスコープを指定しその有効範囲を次のように制限することができます。
- 変数、定数にスコープ宣言した場合、その有効範囲は同じになります。モジュール内で共有したいときPrivate宣言、プロジェクト全体で共有したいときPublic宣言します
- プロシージャは特に指定しないとPublic宣言になります。モジュール間で干渉を防ぎたいときにPrivate宣言を利用します。
このスコープはVBAのプログラムの影響をできるだけ局所化することでプログラムの見通しを良くし、安定したデバッグしやすいコードを書くための仕組みなので、できるだけローカルなスコープを使い、必要に応じてその参照範囲を広げるようにしましょう。
VBEにはモジュール単位で
作成したプログラムをエクスポートしたり
他の人が作ったプログラムをインポートしたり
標準ライブラリと同じように参照できる機能があります。