エクセルVBAで使うコードの備忘録。宣言されたプロシージャ内だけでなく、複数のプロシージャで使用できる変数(グローバル変数)や、複数のモジュール間で使用できる変数(パブリック変数)の使い分けについて。
ローカル変数
通常、変数を使用する際は、プロシージャ(「Sub ~ End Sub」や「Function ~ End Function」の間)で次のように宣言して使用することがほとんどだと思います。このようにプロシージャ内で宣言された変数は、そのプロシージャ内でしか使用できません。このような通常の変数をローカル変数と呼びます。
変数の宣言(ローカル)
Public Sub TestFunction()
'--- 変数を宣言 ---'
Dim val as Long
...
End Sub
グローバル変数
では、複数のプロシージャ間で共通の変数(グローバル変数)を使用したい場合はどのようにすればよいか。グローバル変数の宣言は、プログラムのコードが書かれているモジュール内のすべてのプロシージャよりも前の部分で、ローカル変数と同じように宣言します。
宣言前のPrivateはなくても大丈夫ですが、次に説明するパブリック変数との違いが分かりやすいように明示しています。個人的には、実際にコードを書く際も明記しておくことをお勧めします。きちんと変数が使われる範囲を意識してコードを書くことで、想定外のバグに悩まされる可能性を少しでも下げることができます。
変数の宣言(グローバル)
'--- モジュールの冒頭で宣言 ---'
Private Dim val as Long
'--- プロシージャは変数宣言の後 ---'
Public Sub TestFunction1()
...
End Sub
Private Sub TestFunction2()
...
End Sub
...
Private Sub TestFunctionN()
...
End Sub
パブリック変数
最後にご紹介するパブリック変数は、複数のモジュールにまたがって使用することが可能な変数です。宣言の方法はグローバル変数とほとんど同じですが、PrivateではなくPublicを付けて宣言します。これにより子の変数はすべてのモジュールで共有して使用されます。
変数の宣言(パブリック)
'--- モジュールの冒頭で宣言(Public) ---'
Public Dim val as Long
'--- プロシージャは変数宣言の後 ---'
Public Sub TestFunction1()
...
End Sub
Private Sub TestFunction2()
...
End Sub
...
Private Sub TestFunctionN()
...
End Sub
各変数の優先順位
同じ名前の変数が、ローカル・グローバル・パブリック変数の形で宣言されていた場合(下記のイメージ参照)、プログラムの挙動はどのようになるでしょうか。
モジュール1
'--- グローバル変数(val) ---'
Private Dim val as Long
'--- ローカル変数(val) ---'
Public Sub TestFunction1()
Dim val as Long
...
End Sub
Private Sub TestFunction2()
...
End Sub
Private Sub TestFunction3()
...
End Sub
モジュール2
'--- パブリック変数(val) ---'
Public Dim val as Long
Public Sub TestFunction4()
...
End Sub
Private Sub TestFunction5()
...
End Sub
Private Sub TestFunction6()
...
End Sub
このような状況下で、変数valを使用した場合は、「ローカル変数 > グローバル変数 > パブリック変数」の順番で使用されます。つまり上記の例でいえば、
- ローカル変数が宣言されている「TestFuncion1」プロシージャ内で変数valを使用するとローカル変数のval
- モジュール1内の他のプロシージャ内で変数valを使用するとグローバル変数のval
- モジュール2内ではグローバル変数がないのでパブリック変数のval
が使用されます。
プログラムの挙動イメージとしては、プロシージャ内で変数が使われた場合まずプロシージャ内で同名の変数が宣言されているかどうかが確認され、存在しない場合は同モジュール内を探し、さらに存在しない場合に初めて他のモジュールで宣言されている変数が確認されるという感じになります。
グローバル・パブリック変数は、変数が使用される場所と宣言されている場所が離れているため、変数の範囲を忘れがちになります。バグの温床になるので、特に意図がない限りは、できる限りローカル変数でことを済ませたほうが良いです。