■ スコープを意識してプログラミングしよう!
プログラミング初級者と中級者を大きく隔てる要素の一つにこのスコープの意識があります。
単一のモジュールや数個のユーザーフォームを使ったサブシステムの構築ではあまり意識する必要のなかったスコープの概念も、数十〜百以上のモジュールやフォームを使用した大規模システムを構築する際には、正しくその意味合いを理解している必要があります。
まずスコープの概念ですが、プログラミングの世界では「適用範囲」「有効範囲」という意味でこの言葉は用いられます。
つまり、変数やプロシージャ(関数)が参照される範囲のことを表しています。
たとえば有効範囲の外に置かれた変数や関数は、その識別子で参照することができなくなります。つまりスコープの外にある状態(見えない状態)になっているわけです。
具体的な例をあげたほうがわかりやすいでしょう。
標準モジュール「Module1」に、Sub test() というSubプロシージャを用意しましょう。これは、別のモジュール「Module2」から参照が可能です。Call test で呼び出すことができます。
これは、Sub と定義したプロシージャはPublic を省略したものと同じとみなされるためです。
ではSub test() をPrivate Sub test() にしてみましょう。「Module2」から参照ができなくなりましたね。
変数にも同様にスコープがあります。大きく分けるとローカル変数(局所変数)とグローバル変数(広域変数)に分かれますが、中間のモジュールレベルの変数などもありややこしいです。
さらに変数の適用範囲は、単に変数を参照できる場所を示すだけではなく、値を保持できる時間(期間)にも関わってきます。
いったいなぜこんなことを書くのかというと、識別子(名前)とその適用範囲(スコープ)を適切に管理することが、予期しない誤作動をさけ必要のない参照ができるだけ発生しない、保守性の良いシステムを構築する上でとても重要な意味を持つことを理解してほしいからです。
まず、変数の適用範囲を一覧してみましょう。
■ 変数の適用範囲(有効範囲)
定義される場所 |
Private(Dim) |
Public(Global) |
Static(ステートメント) |
プロシージャ内 |
プロシージャ内でのみ有効、他から参照できない
プロシージャ終了時に値を破棄 |
プロシージャ内ではPuclicの宣言はできない |
プロシージャ内でのみ有効、他から参照できない
プロシージャ終了後も値を保持 |
標準
モジュールの宣言部 |
宣言した標準モジュール内でのみ有効、同一モジュールの他プロシージャからは参照できるが、別モジュールからの参照はできない
プロシージャ終了後も値を保持 |
同一プロジェクト内の全てのモジュールで有効、同一プロジェクト内の全ての他プロシージャから参照できる
プロシージャ終了後も値を保持 |
モジュールの宣言部でStaticの宣言はできない
プロシージャをStatic(キーワード)で宣言することでプロシージャ内のローカル変数を、プロシージャ終了後も値を保持させるようにすることは可能 |
シート・ブック
モジュールの宣言部 |
宣言したシート・ブックモジュール内でのみ有効、同一モジュールの他プロシージャからは参照できるが、別モジュールからの参照はできない
プロシージャ終了後も値を保持 |
フォーム
モジュールの宣言部 |
宣言したフォームモジュール内でのみ有効、同一モジュールの他プロシージャからは参照できるが、別モジュールからの参照はできない
フォーム終了時に値を破棄 |
クラス
モジュールの宣言部 |
宣言したクラスモジュール内でのみ有効、同一モジュールの他プロシージャからは参照できるが、別モジュールからの参照はできない
インスタンス終了時に値を破棄 |
このようになります。
C++やJAVAを知っている方なら、For〜Nextや、If〜End Ifの間で宣言した変数、ブロックレベル変数をご存じだと思いますが、VBAではブロックレベル変数はありませんので注意してください。
ブロック内で宣言した変数もいわゆるプロシージャレベルの変数として扱われます。(ブロック構造を出ても値が破棄されません)
※ プロシージャ終了後も値を保持する変数はEndステートメントで初期化することができます。
※ 参照設定を行うことで、他プロジェクトの広域変数を使用することができるようになります。
1. 参照元ブックと参照先ブックを開く
2. VBEのプロジェクトエクスプローラで参照先プロジェクトを選択
3. ツール>VBAProjectのプロパティを選択 全般タブより、任意のプロジェクト名に変更する
4. プロジェクトエクスプローラで参照元のプロジェクトを選択
5. ツール>参照設定で、3で変更した参照先プロジェクトにチェックをいれる
さて次は、関数(プロシージャ)の有効範囲についてみていきましょう。
■ 関数(プロシージャ)の適用範囲
記述される場所 |
Private |
Public(省略) |
標準モジュール |
宣言した標準モジュール内の他プロシージャからは呼出できるが、別モジュールからの呼出はできない |
同一プロジェクト内の全ての他プロシージャから呼出できる Public(省略)で宣言されたSubプロシージャはマクロの実行から呼出できる |
シート・ブックモジュール |
宣言したシート・ブックモジュール内の他プロシージャからは呼出できるが、別モジュールからの呼出はできない
Public(省略)で宣言されたSubプロシージャはマクロの実行から呼出できる |
フォームモジュール |
宣言したフォームモジュール内の他プロシージャからは呼出できるが、別モジュールからの呼出はできない |
クラスモジュール |
宣言したクラスモジュール内の他プロシージャからは呼出できるが、別モジュールからの呼出はできない
Public(省略)で宣言されたプロシージャはインスタンスのメソッドとして呼出できるがPrivateで宣言されたプロシージャは呼出できない |
このようになります。
変数や関数のスコープを意識してプログラミングすることはとても大切なことです。そして変数・関数のスコープはできる限り局所的であるべきです。
その理由は、どこからでも参照できる変数・関数はプログラマの意図しない値を持ったり、予期しない動きを引き起こす可能性があること、さらにプロシージャが終了しても保持し続ける値がどの時点で初期化されるかを開発者に把握しにくいことが挙げられます。
メモリの浪費を抑えるというメリットもありますが、なにより開発者にとって透明性の高いコーディングをすることが、マクロVBAの中・上級者には大切なことであると思います。
あと初級編では触れませんでしたが、モジュールの宣言領域では必ず Option Explicit を宣言し、全ての変数の宣言を強制してください。VBEの「ツール>オプション>編集>変数の宣言を強制する」チェックで自動的に挿入されるようになります。
|