このページの内容について
このページは、VBAエキスパート(ExcelVBAベーシック)試験合格講座の第四回記事です。第公式テキスト第5章「変数と定数」の内容について解説します。1時間の講義でお話する程度の分量です。講座受講者の復習での利用を想定しています。
変数
変数とは
データを一時的に格納しておく記憶域のことです。Excelのセル1つのようなものです。通常、セルへデータを書き出すよりも変数にデータを格納する方が処理速度が速いです。特に何万行ものデータを扱うと体感速度が大きく異なります。
サンプルコード(クリックでコピー)
Private Sub LoopRange50000()
Dim target_rng As Range
Dim i As Long
Set target_rng = ThisWorkbook.Worksheets(1).Range("A1")
Debug.Print Now
For i = 1 To 50000 Step 1
target_rng.Value = i
Next i
Debug.Print Now
End Sub
Private Sub LoopVariableMillion()
Dim x As Long
Dim i As Long
Debug.Print Now
For i = 1 To 1000000 Step 1
x = i
Next i
Debug.Print Now
End Sub
処理時間の違いを体感しましょう
サンプル上段のコードを実行すると、マクロを実行中のブックの左から1番目のシートのセルA1に5万回データ入力をします。入力前と後の時間がイミディエイトウィンドウに表示さます。下段のコードを実行すると変数に100万回データの格納を実施します。
私のPC環境
サンプル上 ・・・ 12秒
サンプル下 ・・・ 1秒未満
という結果になります。
大した差に見えないかもしれませんが、マクロ実行中に12秒も待たされると不安になるものです。自身の環境でも試してみてください。PCの性能によってはさらに時間がかかると思いますので、繰り返す数値は調整しましょう。
変数の型
変数には型を設定することができ、下記のようなものがあります。Excelのセルの書式のようなものです。
表記 | 型名 | 格納できるデータ |
---|---|---|
Boolean | ブール型 | True/False |
Byte | バイト型 | 整数(0~255) |
Integer | 整数型 | 整数(-32,768~32,767) |
Long | 長整数型 | 整数(-2,147,483,648~2,147,483,647) |
Currency | 通貨型 | 小数点第四位までの数(-92,233,720,385,477.5808~922,337,203,685,477.5807) |
Single | 単精度浮動小数点数型 | 負の値の場合は -3.4028235E+38 から -1.401298E-45 まで、 正の値の場合は 1.401298E-45 から 3.4028235E+38 まで |
Double | 倍精度浮動小数点数型 | 負の値の場合は-1.79769313486231570 E + 308 から -4.94065645841246544 E-324まで 正の値の場合は1.79769313486231570 E + 308まで |
Date | 日付型 | 日付:100年1月1日~9999年12月31日 時刻:0:00:00~23:59:59 |
String | 文字列型 | 最大20億文字 |
Object | オブジェクト型 | オブジェクト |
Variant | バリアント型 | 変数に格納できるすべてのデータ |
変数の宣言
変数を宣言する理由
変数は宣言することができます。宣言をすることで型が一目でわかるため、コードの可読性が向上します。宣言を省略して変数を使用する場合、すべて「Variant」型とみなされます。
変数の宣言方法
「Dim 変数名 As 型」のように記述します。
宣言を省略しても同じ結果になります
Private Sub Test_Decleare()
Dim cnt As Long
cnt = cnt + 1
Debug.Print cnt
End Sub
Private Sub Test_UnDecleare()
cnt = cnt + 1
Debug.Print cnt
End Sub
上記2つのサンプルをそれぞれ実行しても結果は同じです。
変数を宣言しないと起きること
変数の宣言は省略することができますが、宣言をしない場合、どんな変数も有効となってしまい開発者の意図しないエラーが発生することがあります。下記サンプルの実行結果はイミディエイトウィンドウに200が出力されるはずですが、そうなりません。どうすれば200が表示されるでしょうか?修正点を一目で判断できるでしょうか。
Private Sub Test_0O0O()
Dim No_01 As Long
Dim No_02 As Long
No_01 = 100
No_02 = 100
Debug.Print No_01 + No_O2
End Sub
変数の宣言を強制する
変数の宣言はExcelの設定で「強制」することができます。
VBEのオプションを開く
VBEを起動(「Alt」+「F11」)し、リボンの「ツール」⇒「オプション」を開く。
編集タブから「変数の宣言を強制する」を選択
「編集」タブ⇒「変数の宣言を強制する(R)」にチェックを入れて「OK」を押下する
新しいモジュールを作成すると変数の宣言を強制する文言が自動追加されます
設定が完了すると、新しく作成するモジュールの冒頭に「Option Explicit」という文言が自動で追加されるようになります。この文言はこのモジュール内で変数の宣言を強制し、宣言されていない変数がある場合、プロシージャの実行前にコンパイルエラーを発生させるというものです。設定によって変数の宣言が強制されているわけではなく、設定によって変数の宣言を強制する文言が自動追加されるようになったということです。そのため、変数の宣言を強制する設定をしていても手動で文言を削除すれば変数を宣言なしで使用できます。
変数を宣言せずに使用すると起きるエラー
前述のサンプルコードを変数の宣言を強制した状態で実行すると以下のようになり「No_02」と入力されるべき箇所に「No_O2」と入力されていたことがわかります。
宣言の省略記法
マクロが複雑になるほど使用する変数も多くなります。そんな時、複数の宣言を「,(カンマ)」で区切って1行にまとめて書くとコードの行数を抑えることができます。
サンプルコード(クリックでコピー)
Private Sub Test_Decleares()
Dim i As Long, j As Long, k As Long
Dim x, y, z As Long
Stop
End Sub
誤った省略の仕方
上記サンプルを実行すると「Stop」で動作を停止します。そこでローカルウィンドウを開き変数の中身を確認してみましょう。「x」と「y」がLong型ではなく、Variant型になってしまっていることがわかります。
変数の初期値
変数には型に応じてそれぞれ初期値が設定されています。
サンプルコード(クリックでコピー)
Private Sub InitialValue()
Dim bool As Boolean
Dim by As Byte
Dim i As Integer
Dim lng As Long
Dim cur As Currency
Dim sin As Single
Dim dbl As Double
Dim day As Date
Dim str As String
Dim obj As Object
Dim val As Variant
Stop
End Sub
変数の状態はローカルウィンドウから確認しましょう
上記サンプルを実行すると「Stop」で動作を停止します。そこでローカルウィンドウを開き変数の中身を確認してみましょう。
変数への代入
値の代入
代入演算子「=」を使用します。
Private Sub Test_SubstituteValue()
Dim hello As String
Dim today As String
hello = "こんにちは"
today = "2024/11/24"
Call MsgBox(hello & today & "です。")
End Sub
オブジェクトの代入
「Set」と代入演算子「=」を使用します。
Private Sub Test_SubstituteObject()
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ThisWorkbook
Set ws = wb.Worksheets(1)
Debug.Print ws.Name
End Sub
変数の適用範囲(スコープ)
スコープとは
変数は宣言方法や宣言する場所によって使用できる範囲が異なります。この変数を使用できる範囲のことを「変数のスコープ」や「変数の可視範囲」と呼びます。
ローカル変数(局所変数)
ローカル変数とは
ローカル変数とはプロシージャ内で宣言された変数のことです。プロシージャ内で宣言された変数はそのプロシージャ内でしか使用することができません。下記サンプルコードで確認してみ下さい。「Test_Scope」はプロシージャ内で「msg」という変数を宣言し、msgに文字列を代入しています。その後「Test_ScopeSub」を呼び出していますがTest_ScopeSub内でmsgを使おうとしています。
サンプルコード(クリックでコピー)
Private Sub Test_Scope()
Dim msg As String
msg = "これはローカル変数です"
Call Test_ScopeSub
End Sub
Private Sub Test_ScopeSub()
Call MsgBox(msg, vbInformation)
End Sub
変数の宣言を強制しているかによって結果が異なります
上記サンプルコードで「Test_Scope」を実行すると、変数の宣言を強制している場合は「Test_ScopeSub」が呼び出されるときに「変数が定義されていません。」というエラーが発生します。変数の宣言を強制していない場合は、このエラーを回避できますが、「Test_ScopeSub」のmsgは「Test_Scope」のmsgとは別物とみなされるため、空白のメッセージが表示されます。
モジュールレベル変数
モジュールレベル変数とは
変数の宣言はプロシージャの外でも実行することができます。プロシージャの外で宣言された変数は、モジュール内であればどのプロシージャからも使用することができます。下記サンプルでは前述のようなエラーは発生しません。
サンプルコード(クリックでコピー)
Dim msg As String
Private Sub Test_ScopeModule()
msg = "これはモジュールレベル変数です"
Call Test_ScopeModuleSub
End Sub
Private Sub Test_ScopeModuleSub()
Call MsgBox(msg, vbInformation)
End Sub
別のプロシージャ間で変数を共有することができました
上記のサンプルコードで「Test_ScopeModule」を実行するとモジュールレベル変数である「msg」に文字列を代入し「Test_ScopeModuleSub」を呼び出します。呼び出し先ではmsgをメッセージ表示します。モジュール内で変数の共有ができているためエラーが発生せず、また意図した通りのメッセージが表示されます。
パブリック変数(グローバル変数)
モジュールレベル変数の「Dim」や「Private」を「Public」に置き換えて宣言すると別のモジュールからも使用可能な変数となります。サンプルコードでは表現しきれませんので、自身で試してみてください。
変数の有効期間(寿命)
宣言方法による変数の有効期間の違い
プロシージャ内で宣言された変数は、プロシージャの動作が終了すると中身は消えてしまいます。そのため2回目、3回目を実行しても結果は同じです。しかしモジュールレベル変数とパブリック変数はプロシージャ終了後も値が残るため、マクロの内容によっては1回目と2回目で実行結果が変わってしまいます。
サンプルコード(クリックでコピー)
Dim cnt As Long
Private Sub Test_Life()
cnt = cnt + 1
Debug.Print cnt
End Sub
実行結果
上記サンプルを実行すると実行の都度、イミディエイトウィンドウに表示される数値が増えていくことが確認できます。このように、モジュールレベル変数とパブリック変数はプロシージャの動作終了後も値を保持します。
変数の初期化の重要性
上記のように実行の都度結果が変わってしまうマクロは管理上好ましくありません。ユーザーの意図しない結果となってしまうことがあります。意図して実行結果を変えたい場合を除き、原則は変数を初期化して、何度実行しても同じ結果になるマクロを作成しましょう。
サンプルコード(クリックでコピー)
Dim cnt As Long
Private Sub Test_Initialize()
cnt = 0
cnt = cnt + 1
Debug.Print cnt
End Sub
実行結果
上記サンプルを実行すると、何度実行しても結果同じイミディエイトウィンドウに「1」が出力されます。
定数
定数とは
変数は「データを一時的に格納しておく記憶域のこと」です。また、変数は代入演算子を使用してマクロの実行中に何度でも書き換えることができます。定数とは、変数と同じく「データを一時的に格納しておく記憶域のこと」ですが、書き換えることができません。
定数の使い方
変数を宣言するときに使用する「Dim」を「Const」に置き換え、型指定後に続けて代入演算子を記述し、定数に入れる値を指定します。
例)Const TAIYO as String = “Sun”
「TAIYO」という定数を宣言し「Sun」という値を指定しています。
サンプルコード(クリックでコピー)
Private Sub Test_Const()
Const TAIYO As String = "Sun"
Debug.Print TAIYO
TAIYO = "Cloud"
End Sub
実行結果
上記のサンプルは実行しようとしてもエラーが発生します。定数を書き換えようとしているためです。このように、書き換えができないようVBAが管理してくれるため、プログラムを通じて変更する予定のないデータは定数で管理すると事故が少なくなります。
定数のスコープ
変数と同様です。宣言する場所や宣言の方法によって使用できる範囲を変更することができます。
サンプルコード(クリックでコピー)
Private Const KUMO As String = "cloud"
Const TAIYO As String = "Sun"
Private Sub Test_ModuleConst()
Debug.Print TAIYO
End Sub
Private Sub Test_PrivateConst()
Debug.Print KUMO
End Sub
実行結果
上記のサンプルはどちらも定数の内容をイミディエイトウィンドウに出力します。「Private」は記述しても省略しても動きは同じです。
定数を使ったサンプル(応用編)
このサンプルは難易度が高いので読み飛ばしOKです。
サンプルコード(クリックでコピー)
Private Property Get wsh() As Object
Static Obj As Object
If Obj Is Nothing Then Set Obj = CreateObject("WScript.Shell")
Set wsh = Obj
End Property
Private Sub Test_YesConst()
Const URL_TOP As String = "https://funcref.com/{@page}"
Const LESSER As String = "lesserscraping/"
Const VBA_EX As String = "vbaexpertlesson/"
Const FIND_KEY As String = "{@page}"
Dim url As String
url = Replace(URL_TOP, FIND_KEY, VBA_EX)
Call wsh.Run(url)
url = Replace(URL_TOP, FIND_KEY, LESSER)
Call wsh.Run(url)
End Sub
Private Sub Test_NoConst()
Dim url As String
url = Replace("https://funcref.com/{@page}", "{@page}", "vbaexpertlesson/")
Call wsh.Run(url)
url = Replace("https://funcref.com/{@page}", "{@page}", "lesserscraping/")
Call wsh.Run(url)
End Sub
定数を使用する理由
上記、サンプルコードを実行すると、マクロを実行する人(ユーザー)のPCに設定されているデフォルトのブラウザを使用して当サイトの「VBAエキスパート」「LesserScraping」ページをそれぞれ開きます。プロシージャは2つ記述していますが、それぞれ同じ結果になります。見比べるとわかるように、定数を使用しない場合、宣言部がない分コードは短くなっています。しかし、処理部分のコードはひとつひとつの単語が長く、読みづらいです。定数を使用することで処理部分をすっきりさせることができ、また、書き換えができないため誤って書き換えてしまうこともなくなります。
Comment