変数の適用範囲(スコープ)

<< ユーザー定義型の宣言と型変換 :前の記事

前回はユーザー定義型の作成と宣言について解説しました。一度設定した型宣言の変換についてもVBA関数を利用すれば変更できることが分かったかと思います。今回は変数が及ぼす影響の範囲について解説していきます。

また、こちらでは、まだ解説していないプロシージャ引数・戻り値を利用しています。そちらについては追々解説していきますので、今回は事例のプロシージャの実行結果の確認に留め、変数がどのように適用されるかを重点的に理解するようにしましょう。

目次

変数の適用範囲(スコープ)とは

変数には適用範囲とういものがあります。その適用範囲のことをスコープと呼びます。一度宣言した変数はいつでもどこでも利用できるというわけではなく、宣言方法や宣言した場所によって適用範囲が異なります。こちらでは事例を交えてそれぞれの適用範囲について解説していきます。

プロシージャ内で宣言した変数(Dimステートメント)

プロシージャ内で宣言した変数は、その宣言したプロシージャ内で有効となります。プロシージャ内での宣言は、「プロシージャレベルの宣言」と言い、宣言したプロシージャ内でしか使用できない変数を「ローカル変数」と呼びます。以下の処理で変数の適用範囲について、ご確認ください。


Sub sampleA()
    
    Dim a As Integer
    
    a = 5
    
    MsgBox "sampleAプロシージャの変数a:" & a
    
    Call sampleB
    
    MsgBox "sampleAプロシージャの変数a:" & a

End Sub

Sub sampleB()
    
    Dim a As Integer
    
    a = 10
    
    MsgBox "sampleBプロシージャの変数a:" & a
    
End Sub

実行結果

こちらは、sampleAプロシージャを実行した結果です。

プロシージャ内宣言の適用範囲

解説

こちらのsampleAプロシージャとsampleBプロシージャにはDimステートメントを利用してプロシージャ内で変数aを宣言しています。

sampleAプロシージャの変数aに「5」を、sampleBプロシージャの変数aに「10」を代入しています。どちらも同じ変数名ですが、設定値が異なっているのが分かるかと思います。

sampleAプロシージャの実行結果を見ると変数aの値は「5」→「10」→「5」になっています。最初の「5」は、sampleAプロシージャ内で宣言した変数aが適用されています。次に「10」は他のプロシージャを呼び出すCallステートメントを利用してsampleBプロシージャを呼び出した結果です。
「10」の値はsampleBプロシージャ内で宣言した変数aが適用されています。最後の「5」は、またsampleAプロシージャ内で宣言した変数aが適用されています。

このように同じ変数名であってもプロシージャ内で宣言した変数は、プロシージャ内で有効であることが分かります。

プロシージャレベルの宣言

プロシージャ内で宣言した変数(Staticステートメント)

プロシージャ内のDimステートメントで宣言された変数は処理が完了すると変数が初期化される性質を持ちますが、用途によっては処理が完了しても変数の値を保持したい場合があります。

そのような場合に利用されるのがStaticステートメントです。Staticステートメントで宣言した変数は、1度行った処理で保持した値を処理が行われた後も保持し続けます。それでは、以下の処理で値がどのように保持されるのかをご確認ください。


Sub sampleA()
    
    Static a As Integer
    
    a = a + 1
    
    MsgBox a & "回目に処理です。"
    
End Sub

実行結果

こちらは、sampleAプロシージャを3回実行した結果です。

Staticステートメントの結果

解説

こちらは、Staticステートメントを利用してプロシージャ内で変数aを宣言し、sampleAプロシージャを3回実行しています。「a=a+1」は代入演算子変数aに1足した値になり、1→2→3のように値が足し算されます。

このように値を保持して処理を行いたい場合は、Staticステートメントを利用するようにしましょう。また、Staticステートメントを宣言できるのはプロシージャ内になりますので、ご注意ください。

宣言セクション内で宣言した変数(Dim・Privateステートメント)

宣言セクション内(モジュールの先頭)で宣言した変数は、その宣言したモジュール内で有効となります。宣言セクション内での宣言は、「モジュールレベルの宣言」と言い、1つのモジュール内にあるすべてのプロシージャで使用できる変数は「モジュール変数」と呼ばれます。以下の処理で変数の適用範囲について、ご確認ください。


Dim a As Integer

Sub sampleA()

    a = 5
    
    MsgBox "sampleAプロシージャの変数a:" & a
    
    Call sampleB
    
    MsgBox "sampleAプロシージャの変数a:" & a

End Sub

Sub sampleB()

    a = 10
    
    MsgBox "sampleBプロシージャの変数a:" & a
    
End Sub

実行結果

こちらは、sampleAプロシージャを実行した結果です。

モジュール内宣言の適用範囲

解説

こちらは、Dimステートメントを利用して宣言セクション内で変数aを宣言しています。sampleAプロシージャの実行結果を見ると変数aの値は「5」→「10」→「10」になっており、プロシージャ内で宣言した変数結果と異なった結果になりました。

最初の「5」は、sampleAプロシージャ内で設定した変数a=5が適用されています。次の「10」は、sampleBプロシージャ内で設定した変数a=10が適用されています。宣言セクション内で宣言した変数はモジュール内で有効ですので、この時点のsampleAプロシージャの変数a「10」が代入されています。

よって、最後に実行したMsgBox関数では、「10」で表示されたということです。このように同じ変数名であっても宣言セクション内で宣言した変数は、モジュール内で有効であることが分かります。

モジュールレベルの宣言

Dimステートメント以外にも同様の動作をするPrivateステートメントもあります。Privateステートメントを利用して宣言セクション内で宣言した変数もモジュール内で有効となります。以下は事例ですので、Dimステートメントと同様の結果になっているのをご確認ください。


Private a As Integer

Sub sampleA()

    a = 5
    
    MsgBox "sampleAプロシージャの変数a:" & a
    
    Call sampleB
    
    MsgBox "sampleAプロシージャの変数a:" & a

End Sub

Sub sampleB()

    a = 10
    
    MsgBox "sampleBプロシージャの変数a:" & a
    
End Sub
モジュール内宣言の適用範囲

また、モジュール内でもStaticステートメントのように値を保持したい場合がありますが、Staticステートメントプロシージャ内でしか記述できません。モジュール内で値を保持したい場合どのように設定するかということ、特になにもする必要はありません。モジュールレベルで宣言した変数は自動的にモジュール実行中の間は値が保持されます


Dim a As Integer

Sub sampleA()
    
    a = a + 1
    
    MsgBox a & "回目に処理です。(sampleA)"
    
End Sub

Sub sampleB()

    a = a + 1
    
    MsgBox a & "回目に処理です。(sampleB)"
    
End Sub

以下はsampleA→sampleA→sampleBの順に実行した結果です。モジュール内で値が保持されているのが分かるかと思います。

モジュールレベルの値の保持

宣言セクション内で宣言した変数(Publicステートメント)

モジュール内で有効な変数宣言について理解できたかと思いますが、複数のモジュール間で変数を利用したい場合もあります。そのような場合には、Publicステートメントを利用して宣言します。宣言セクション内で宣言したPublicステートメントの変数は、すべてのモジュールで有効となります。このようにすべてのモジュールで使用できる変数は「パブリック変数」と呼ばれます。

まずは、Dimステートメントで宣言した変数がモジュール間でどのような値をとるか確認してみます。こちらではModule1にsampleAプロシージャをModule2にsampleBプロシージャを記述しています。sampleプロシージャを実行した結果を見ると変数aの値は「5」→「10」→「5」になっています。

最初の「5」は、Module1のsampleAプロシージャ内で設定した変数aが適用されています。次に「10」は他のプロシージャを呼び出すCallステートメントを利用してModule2のsampleBプロシージャを呼び出した結果です。

「10」の値はsampleBプロシージャ内で設定した変数aが適用されています。最後の「5」は、またsampleAプロシージャ内で設定した変数aが適用されています。

Module1


Dim a As Integer

Sub sampleA()

    a = 5
    
    MsgBox "sampleAプロシージャの変数a:" & a
    
    Call sampleB
    
    MsgBox "sampleAプロシージャの変数a:" & a

End Sub

Module2


Sub sampleB()

    a = 10
    
    MsgBox "sampleBプロシージャの変数a:" & a
    
End Sub
宣言セクション内のDimステートメント変数宣言セッション内宣言の適用範囲

宣言セクション内でDimステートメントを利用した場合はモジュール間で利用できないことが分かったかと思います。続いてPublicステートメントを利用した事例を見ていきましょう。

Module1


Public a As Integer

Sub sampleA()

    a = 5
    
    MsgBox "sampleAプロシージャの変数a:" & a
    
    Call sampleB
    
    MsgBox "sampleAプロシージャの変数a:" & a

End Sub

Module2


Sub sampleB()

    a = 10
    
    MsgBox "sampleBプロシージャの変数a:" & a
    
End Sub
宣言セクション内のPublicステートメント変数

実行結果

こちらは、sampleAプロシージャを実行した結果です。

モジュール内宣言の適用範囲

解説

こちらは、Publicステートメントを利用して宣言セクション内で変数aを宣言しています。sampleAプロシージャの実行結果を見ると変数aの値は「5」→「10」→「10」になっています。

最初の「5」は、sampleAプロシージャ内で設定した変数a=5が適用されています。次の「10」は、sampleBプロシージャ内で設定した変数a=10が適用されています。Publicステートメントで宣言した変数はすべてのモジュールで有効ですので、この時点のsampleAプロシージャの変数a「10」が代入されています。

よって、最後に実行したMsgBox関数では、「10」で表示されたということです。続いてPublicステートメントを利用してモジュール間でも値が保持されるのかも確認してみます。以下の処理をご確認ください。

Module1


Public a As Integer

Sub sampleA()
    
    a = a + 1
    
    MsgBox a & "回目に処理です。(sampleA)"
    
End Sub

Module2


Sub sampleB()

    a = a + 1
    
    MsgBox a & "回目に処理です。(sampleB)"
    
End Sub

以下はsampleA→sampleA→sampleBの順に実行した結果です。モジュール間でも値が保持されているのが分かるかと思います。

モジュールレベルの値の保持

変数の有効期限

ここまで変数の適用範囲と値の保持される期間について解説してきました。変数が値を保持する期間は「変数の有効期限」と呼ばれます。

ローカル変数は、プロシージャが実行されるごとに「0」に初期化され、そのプロシージャが実行されている間のみ値が保持されます。

モジュール変数は、ブックを閉じるまで値が保持され、プロシージャ内にあるモジュール変数はそのプロシージャを繰り返し実行しても初期化されることはなく、値が保持されます。

このように変数を宣言する場所は宣言ステートメントで有効期限が変わってきますので、以下の表を参考に覚えておきましょう。

宣言場所ステートメント適用範囲有効期間
プロシージャ内Dim宣言プロシージャ内プロシージャ実行中のみ
プロシージャ内Static宣言プロシージャ内ブックを開いている間
宣言セクションDim宣言モジュール内モジュール実行中のみ
宣言セクションPrivate宣言モジュール内モジュール実行中のみ
宣言セクションPublicすべてのモジュール内ブックを開いている間

ユーザー定義型の範囲

Typeステートメントを利用してユーザー定義型の宣言を行う場合も適用範囲を指定できます。ユーザー定義型で利用できるキーワードは「Private」と「Public」の2種類になります。キーワードはTypeステートメントの先頭に記述することで利用できます。それでは、それぞれどのように処理されるか確認してみましょう。

キーワードPrivate

Module1


Private Type Personal
    Name As String
    Age As Byte
End Type

Sub sampleA()
    
    Dim perA As Personal
    
    perA.Name = "鈴木"
    perA.Age = 20
    
    MsgBox "名前:" & perA.Name & ", 年齢:" & perA.Age
    
End Sub

Module2


Sub sampleB()

    Dim perA As Personal
    
    perA.Name = "田中"
    perA.Age = 30
    
    MsgBox "名前:" & perA.Name & ", 年齢:" & perA.Age
    
End Sub

Module2のsampleBプロシージャを実行した結果です。

ユーザー定義型のエラー

キーワードPrivateで宣言したユーザー定義型はモジュール内のみで有効となります。Module2のsampleBプロシージャは他のモジュールですので、sampleBプロシージャを実行するとコンパイルエラーで「コンパイルエラー:ユーザ定義型は定義されていません。」と表示されます。

キーワードPublic

Module1


Public Type Personal
    Name As String
    Age As Byte
End Type

Sub sampleA()
    
    Dim perA As Personal
    
    perA.Name = "鈴木"
    perA.Age = 20
    
    MsgBox "名前:" & perA.Name & ", 年齢:" & perA.Age
    
End Sub

Module2


Sub sampleB()

    Dim perA As Personal
    
    perA.Name = "田中"
    perA.Age = 30
    
    MsgBox "名前:" & perA.Name & ", 年齢:" & perA.Age
    
End Sub

sampleBをプロシージャを実行した結果です。

ユーザー定義型の取得

キーワードPublicで宣言したユーザー定義型はすべてのモジュール内で有効となります。ですので、Module2のsampleBプロシージャを実行してもコンパイルエラーとならず、実行結果のように表示されます。

尚、ユーザー定義型の既定値はキーワードPublicですので、キーワードを記述しない場合は常にキーワードPublicが適用されます

まとめ

今回は、変数の有効範囲と有効期間について解説しました。変数を宣言する場所によって値が変化するのが確認できたかと思います。ここまで変数には1つの値を代入してきましたが、変数には複数の値を代入することもできます。その際に利用されるのが配列です。次回は、この配列について解説します。

次の記事: VBAの配列とは >>

Excel VBAでIEを思いのままに操作できるプログラミング術 Excel 2013/2010/2007/2003対応

近田 伸矢, 植木 悠二, 上田 寛

IEのデータ収集&自動操作のプログラミング本はこの1冊だけ!IEの起動やポップアップウィンドウ、表示を制御する基本的なコードはもちろん、テキストボックスやラジオボタン、表、ハイパーリンクなどのHTML部品を制御する方法など、自動操作に欠かせないノウハウを丁寧に解説。

  • このエントリーをはてなブックマークに追加
ExcelのVBAについてのQ&A掲示板

↑ExcelのVBA全般について分からない事があればこちらの掲示板よりご質問ください^^

VBAのInternetExplorer操作入門

↑ExcelのVBAをマスターできたら、エクセルVBAのIE(InternetExplorer)操作にも挑戦してみてください^^

VBAのIE制御入門RSS

RSSフィードを登録すると最新記事を受け取ることができます。

VBAIE操作のスカイプレッスン

エクセルVBAのステートメント

こちらでは、エクセルVBAの事例で利用したステートメントをまとめたものです。ExcelのVBAには様々な機能が用意されていますので一度ご確認ください。

エクセルVBAのオブジェクト

こちらでは、エクセルVBAの事例で利用したオブジェクトをまとめたものです。ExcelのVBAには様々な機能が用意されていますので一度ご確認ください。

エクセルVBAのプロパティ

こちらでは、エクセルVBAの事例で利用したオブジェクトのプロパティをまとめたものです。ExcelのVBAには様々な機能が用意されていますので一度ご確認ください。

エクセルVBAのメソッド

こちらでは、エクセルVBAの事例で利用したオブジェクトのメソッドをまとめたものです。ExcelのVBAには様々な機能が用意されていますので一度ご確認ください。

エクセルVBAのイベント

こちらでは、エクセルVBAの事例で利用したオブジェクトのイベントをまとめたものです。ExcelのVBAには様々な機能が用意されていますので一度ご確認ください。