変数のスコープについて
EXCEL VBAの基本コードを紹介しています。初心者の方が順番に読んでくだけでVBAの基礎コードが理解出来るようになればなと思って、短めの記事で進めて行きたいと思います!
今回は、”スコープについて”について紹介します!
スコープ
「スコープ」って言っても馴染みのない言葉ですね。でもプログラミングする上では、意識しておかないといけないことなので説明します!
これまで変数について色々とやってきました。実は変数には、それを参照できる範囲が決まっています。この決まってる範囲が”スコープ”という名前で呼ばれています。
グローバル領域
実はVBAでは、どのプロシージャにも属さない場所(一番上の部分)に変数を宣言することができます。その部分をグローバル領域と言います。次の図のような場所です。
図では、グローバル領域に次の3つの変数を宣言をしています。
① Public pub_Name As String
② Dim dim_Name As String
③ Private pri_Name As String
②はこれまでもよく使ってきた「Dim」なので分かると思いますが、他にも「Public」「Private」を使って変数を宣言することができます。
この宣言時に頭につけるものと、そもそも宣言を書く場所で、スコープの範囲が違ってきます。
グローバル領域でPublicで変数を宣言
グローバル領域で、Publicで変数を宣言すると、プロジェクト内のどの場所からも変数を参照することができます。
まずは同じModule1内から参照出来るか次のコードで試します。
' グローバル領域
Public pub_Name As String
'プロシージャ1
Sub test1()
pub_Name = "パブひらちん"
Debug.Print "test1内:" & pub_Name
Call test2 'test2の呼び出し
End Sub
'プロシージャ2
Sub test2()
Debug.Print "test2内:" & pub_Name
End Sub
test1とtest2を実行します。
test1は、グローバル領域で宣言した変数pub_Nameに、「パブひらちん」を代入して、イミディエイトウィンドウに表示させ、その後test2プロシージャを呼び出します。
test2はtest2の中からグローバル変数を呼び出して、イミディエイトウィンドウに表示させるコードです。
test1を実行します。
test1からもtest2からも、設定した変数pub_Nameを参照できていることが分かります。
次に別のModuleから参照出来るか確認してみましょう。Module1・Module2に次のようにコードを記述します。
' グローバル領域
Public pub_Name As String
'プロシージャ1
Sub test1()
pub_Name = "パブひらちん"
Debug.Print "test1内:" & pub_Name
Call test3 'test3の呼び出し
End Sub
'プロシージャ3
Sub test3()
Debug.Print "test3内:" & pub_Name
End Sub
test1から、test3を呼び出します。test3には、Module1で宣言した、変数のpub_Nameを呼び出してイミディエイトウィンドウに表示させるコードを記述しています。
test1を実行しましょう。
別のModuleに記述されたtest3からも、pub_Nameが参照できていることが分かります。
グローバル領域でPrivete(Dim)で変数を宣言
グローバル領域でPrivate(またはDim)で変数を宣言した場合、宣言をしたModule内だけで変数の参照ができます。
これもサンプルで試してみます。まずは、宣言したModule1の中で参照出来るか試してみましょう。
' グローバル領域
Private pri_Name As String
Dim dim_Name As String
'プロシージャ1
Sub test1()
pri_Name = "プラひらちん"
Debug.Print "test1内:" & pri_Name
dim_Name = "ディムひらちん"
Debug.Print "test1内:" & dim_Name
Call test2 'test2の呼び出し
End Sub
'プロシージャ2
Sub test2()
Debug.Print "test2内:" & pri_Name
Debug.Print "test2内:" & dim_Name
End Sub
PrivateとDimで宣言した、変数(それぞれ、pri_Name、dim_Name)を、test1内とtest2を呼び出してtest2内で参照出来るか確認します。
test1を実行します。
同一Module内では、Publicのときと同じように参照出来ることが確認できました。
それでは、Module2にtest3を作成して、そこで参照出来るかどうか確認しましょう。
Module1とModule2をそれぞれ次のようにします。
' グローバル領域
Private pri_Name As String
Dim dim_Name As String
'プロシージャ1
Sub test1()
pri_Name = "プラひらちん"
Debug.Print "test1内:" & pri_Name
dim_Name = "ディムひらちん"
Debug.Print "test1内:" & dim_Name
Call test3 'test3の呼び出し
End Sub
'プロシージャ3
Sub test3()
Debug.Print "test3内:" & pub_Name
Debug.Print "test3内:" & dim_Name
End Sub
test1から別Moduleに作成したtest3を呼び出して、参照出来るかどうか確認します。
test1を実行します。
Publicのときとは違い、変数宣言と別のモジュールに書かれたtest3からは、変数が参照できていないことが分かります。
プロシージャ内でDimで宣言
次は、宣言を書く場所を変えて、プロシージャ内で変数の宣言を行ったときのスコープについて確認します。
プロシージャ内では、Dimでのみ宣言が可能です。PublicやPrivateで宣言するとエラーになってしまいます。
サンプルコードで、まずは同一モジュール内の別プロシージャから参照出来るか確認します。
' グローバル領域
'プロシージャ1
Sub test1()
Dim dim_Name As String
dim_Name = "ディムひらちん"
Debug.Print "test1内:" & dim_Name
Call test2 'test2の呼び出し
End Sub
'プロシージャ2
Sub test2()
Debug.Print "test2内:" & dim_Name
End Sub
変数宣言をしたtest1の中では、変数の参照ができていますが、別プロシージャのtest2からは参照できていないことが分かります。
念のため、別モジュールに書いたtest3も確認しましょう。
Module1とModule2を次のように修正します。
' グローバル領域
'プロシージャ1
Sub test1()
Dim dim_Name As String
dim_Name = "ディムひらちん"
Debug.Print "test1内:" & dim_Name
Call test3 'test3の呼び出し
End Sub
'プロシージャ3
Sub test3()
Debug.Print "test3内:" & dim_Name
End Sub
test1を実行します。
まぁ予想通りですが、test3からは参照できませんでしたね笑
注意点
ここまで読むと、じゃあPublic変数の方が便利じゃん??と思う方もいるかもしれません。確かに、小さなプログラムではその方が良い場合もあるかもしれません。しかし、沢山の関数・プログラムを書いて行くと、どこでどんな名前の変数を付けたのか分からなくなってしまいます。Public変数は、どこからでも参照、つまり書き換えも出来てしまうので、意図しない場所で違う意味で使っている変数を書き換えてしまう現象が起こってしまうかもしれません。重大なエラーを引き起こす可能性もありますので、できるだけ使わない方が良いと思います。
まとめ
スコープについて説明しました!スコープを意識して、適切なプログラムを書くことは重要ですので、しっかり覚えましょう!
コメント