変数の適用範囲(スコープ)
<< ユーザー定義型の宣言と型変換 :前の記事
前回はユーザー定義型の作成と宣言について解説しました。一度設定した型宣言の変換についてもVBA関数を利用すれば変更できることが分かったかと思います。今回は変数が及ぼす影響の範囲について解説していきます。
また、こちらでは、まだ解説していないプロシージャの引数・戻り値を利用しています。そちらについては追々解説していきますので、今回は事例のプロシージャの実行結果の確認に留め、変数がどのように適用されるかを重点的に理解するようにしましょう。
目次
- 変数の適用範囲(スコープ)とは
- プロシージャ内で宣言した変数(Dimステートメント)
- プロシージャ内で宣言した変数(Staticステートメント)
- 宣言セクション内で宣言した変数(Dim・Privateステートメント)
- 宣言セクション内で宣言した変数(Publicステートメント)
- 変数の有効期限
- ユーザー定義型の範囲
- まとめ
変数の適用範囲(スコープ)とは
変数には適用範囲とういものがあります。その適用範囲のことをスコープと呼びます。一度宣言した変数はいつでもどこでも利用できるというわけではなく、宣言方法や宣言した場所によって適用範囲が異なります。こちらでは事例を交えてそれぞれの適用範囲について解説していきます。
プロシージャ内で宣言した変数(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ステートメントを利用してプロシージャ内で変数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ステートメントを利用した場合はモジュール間で利用できないことが分かったかと思います。続いて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
実行結果
こちらは、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の配列とは >>
近田 伸矢, 植木 悠二, 上田 寛
IEのデータ収集&自動操作のプログラミング本はこの1冊だけ!IEの起動やポップアップウィンドウ、表示を制御する基本的なコードはもちろん、テキストボックスやラジオボタン、表、ハイパーリンクなどのHTML部品を制御する方法など、自動操作に欠かせないノウハウを丁寧に解説。