こんにちは、フリーランスエンジニア兼ライターのワキザカ サンシロウです。
皆さんは、VBAで変数の適用範囲(スコープ)を意識したことがありますか?
スコープを意識すると、変数を便利に使うことができるので覚えておくととても便利です。
そこで今回は、
・変数とは
・変数のスコープとは
といった基礎的なことから、
・変数のスコープの使い分け方法
・グローバル変数のおすすめの使い方
といった応用的な方法まで、徹底的に解説します!
変数とは
変数とは、値を保存しておくことができる箱のようなものです。
値を入れたり、使ったりすることができます。
次のように書くことで、変数を使うことができます。
Dim 変数名 as 型名 変数名 = 値
型名で整数、小数、文字列など何を入れる箱なのか宣言してから、値を入れて使います。
例えば、次のようなイメージです。
変数サンプルコード:
Sub Test() Dim intData1 As Integer '整数 Dim dblData2 As Double '小数 Dim strData3 As String '文字列 '変数に値を入れる intData1 = 10 dblData2 = 3.14 strData3 = "こんにちわ" '変数の値をメッセージで確認 MsgBox "intData1:" & intData1 & vbCrLf & _ "dblData2:" & dblData2 & vbCrLf & _ "strData3:" & strData3 End Sub
実行結果:
このように、「Dimで変数の名前と型を決める → 変数に値を入れる → 使いたい場所で変数名を使う」の流れで簡単に変数を使うことができます。
変数の使い方については以下で詳しく解説しているので、気になる方は見てみてくださいね!
変数の適用範囲(スコープ)とは
次に、変数の適用範囲(スコープ)について解説します。
変数は、書く場所・書き方によって使える範囲が変わります。
・Dimでプロシージャ内:プロシージャのみ使える
・Dimでプロシージャ外:モジュール内で使える
・Publicでプロシージャ外:プロジェクト全体でどこからでも使える
言葉だけだとわかりづらいので、それぞれサンプルを交えて解説しますね。
プロシージャ内でのみ使う方法
まずは、プロシージャ内でのみ使う方法です。
VBAは次のような構成でデータができています。
プロジェクトの下に複数のモジュールがあり、モジュールの下に複数のプロシージャがあるイメージですね。
プロシージャ内でのみ使える変数を宣言することができます。
変数を学んだ時に最初に書くのがSubプロシージャの中なので、この方法を使っている人は多いと思います。
サンプルコード:
Sub Test1() Dim intNum as Integer intNum = 123 End Sub Sub Test2() Dim strMessage as String strMessage = "こんにちは" End Sub
Test1で宣言したintNumはTest1のみで使える変数で、Test2で宣言したstrMessageはTest2のみで使える変数です。
このように、Sub内でDimで宣言した変数は、同じプロシージャ内でのみ使える変数になります。
モジュール内でのみ使う方法
次は、同じモジュール内で使う方法です。
先ほどの図でいうと、次のように赤枠で囲った部分がモジュール内で使える変数となります。
モジュール内には複数のプロシージャを作れるので、複数のプロシージャをまたいで使うことができる変数を作ることができます。
サンプルコード:
Dim intNum As Integer Dim strMessage As String Sub Test1() intNum = 1 strMessage = "Test1のメッセージ" Debug.Print "intNum:" & intNum & vbCrLf & _ "strMessage :" & strMessage End Sub Sub Test2() intNum = 2 strMessage = "Test2のメッセージ" Debug.Print "intNum:" & intNum & vbCrLf & _ "strMessage :" & strMessage End Sub
Test1実行結果:
1 Test1のメッセージ
Test1実行結果:
2 Test2のメッセージ
モジュールの先頭にintNumとstrMessageを宣言し、Test1、Test2どちらでも変数を使えていますよね。
このように、プロシージャの外に変数を宣言することで、モジュール内であればどこでも使える変数として使うことができます。
プロジェクト全体で使う方法
つぎに、プロジェクト全体で使う方法について解説します。
先ほどの図でいうと、次の赤枠で囲った部分が範囲になります。
モジュールをまたいでどこからでも使える変数で、グローバル変数とも呼ばれています。
サンプルコードModule1:
Public intNum As Integer Public strMessage As String
サンプルコードModule2:
Sub Test1() intNum = 1 strMessage = "Module2.Test1のメッセージ" Debug.Print "intNum:" & intNum & vbCrLf & _ "strMessage :" & strMessage End Sub
サンプルコードModule3:
Sub Test2() intNum = 2 strMessage = "Module3.Test2のメッセージ" Debug.Print "intNum:" & intNum & vbCrLf & _ "strMessage :" & strMessage End Sub
Test1実行結果:
intNum:1 strMessage :Module2.Test1のメッセージ
Test2実行結果:
intNum:2 strMessage :Module3.Test2のメッセージ
Module1にPublicで作ったグローバル変数intNum、strMessageがModule2のTest1、Module3のTest2でそれぞれ使えていますよね。
このように、モジュールをまたいでどこからでも使うことができます。
ちなみに、グローバル変数については以下で詳しく解説しているので、気になる方は見てみてくださいね!
合わせて覚えると便利なグローバル変数の使い方
ここまでの説明を聞いて、
「どこからでも使える変数の方が便利だし、全部グローバル変数でいいのでは・・・?」
と思った方もいるのではないでしょうか。
確かに使いやすくなるので便利なのですが、その分データが書き換えられやすくなるデメリットがあります。
例えば、次のようなケースです。
Module1:
Public taxRate As Integer '税率
Module2:
'メイン処理 Sub Main() '税率を設定 taxRate = 1.08 '合計金額を表示 Call Module3.Test1(1000, 1) End Sub
Module3:
'合計金額を表示するプロシージャ Sub Test1(cost As Long, num As Long) '税率を設定 taxRate = 1.05 '合計金額を計算 Dim totalCost As Long totalCost = cost * num * taxRate '合計金額を出力 Debug.Print "合計金額:" & totalCost End Sub
Module2のMain実行結果:
合計金額:1050
Module1のグローバル変数taxCost(税率)を、Module2のMainプロシージャ内の最初で1.08(消費税8%)として設定しているにもかかわらず、誤ってModule3の合計金額を計算するTest1の先頭でも1.05(消費税率5%)として設定してしまっているため、Mainプロシージャを実行した結果が「合計金額:1050」になっています。
このように、どこからでも値が書き換えられてしまうため、グローバル変数を使うときは注意が必要です。
そのため、グローバル変数は値が途中で書き換えられない定数として使うのがおすすめです!
グローバル変数を定数で置き換えたサンプル:
Public Const taxRate = 1.08
定数は値を書き換えることができないため、他のモジュールで書き換えるリスクをなくして使うことができます。
詳しい使い方については以下で解説しているので、気になる方は見てみてくださいね!
まとめ
今回は、変数の適用範囲について解説しました。
スコープの違いが判ると、用途に応じて便利に変数を使うことができます。
プロシージャ内・モジュール内・プロジェクト全体で使う方法を覚えておけば応用がきくので、ぜひ使ってみてくださいね!