VBA Public や Private 変数のスコープ

はじめに

Excel VBA マクロで Public や Private 変数、関数のスコープを紹介します。

スコープとは、変数や関数などを参照できる範囲のことです。スコープには次のものがあります。

  • Public 変数や関数:すべてのシートや標準モジュールから参照できます。グローバル変数とも言います。
  • Private 変数や関数:宣言したシートや標準モジュールから参照できます。
  • Dim 変数:宣言した関数から参照できます。関数の定義には使用できません。

スコープを省略したときの既定値は変数や関数で違います。混乱しないように省略しないのをオススメします。

  • 目次
    • Dim 変数
    • Private 変数
    • Public 変数
    • Public、Private 関数
    • その他のスコープ
    • まとめ

Dim 変数

関数の中に Dim で変数を宣言します。その関数から参照できます。この変数のことを「ローカル変数」と言います。

Dim は関数には使えません。変数にのみ使用できます。

ローカル変数をカウントアップする関数を何度実行しても、結果は変わりません。

Sub 実行()
    Call サブ ' 1
    Call サブ ' 1 カウントは増えません
End Sub

Sub サブ()
    Dim ローカル As Integer
    ローカル = ローカル + 1
    Debug.Print(ローカル)
End Sub ' 関数を抜けるとローカル変数は削除される

これは関数を抜けるとローカル変数が削除されるためです。次に同じ関数を実行するときに、ローカル変数の値は初期化されています。

また他の関数からローカル変数を参照できないので、同じ名前の変数を宣言できます。

Sub 実行1()
    Dim 変数 As String

End Sub

Sub 実行2()
    Dim 変数 As String ' 実行1 とは別の変数です

End Sub

このように、その関数内でのみ使用する変数を作成したいときに Dim を使用します。

Private 変数

すべての関数より上に Private で変数を宣言します。宣言したファイル内から参照できます。マクロの実行が終了した後も値が残ります。

Private プライベート As Integer

Sub 実行()
    Call カウントアップ ' 1
    Call カウントアップ ' 2
    Call カウントダウン ' 1
End Sub

Sub カウントアップ()
    プライベート = プライベート + 1
    Debug.Print(プライベート)
End Sub

Sub カウントダウン()
    プライベート = プライベート - 1
    Debug.Print(プライベート)
End Sub

別シートなど別ファイルから Private 変数を参照できないので、ファイルごとに同じ名前の変数を宣言できます。

' Sheet1 のコード
Private 変数 As Integer

' Sheet2 のコード
Private 変数 As Integer ' Sheet1 とは別の変数です

このように複数の関数で同じ変数を使いたいときや、関数を抜けても値を残したいときに Private を使用します。

マクロが終了しても変数の値が残るので、マクロを実行するときに初期化する必要があります。詳しくは次の「Public 変数」をご覧ください。

関数の外でも Dim を使って変数を宣言できます。そのときは Private と同じ扱いになります。ローカル変数と混同するので Private を使用します。

Public 変数

すべての関数より上に Public で変数を宣言します。すべてのファイルから参照できます。この変数のことを「グローバル変数」と言います。マクロの実行が終了した後も値が残ります。

別ファイルの Public 変数を参照するには ファイル名.変数名 のように、変数の前にそのファイル名を入力します。標準モジュールの変数は、ファイル名を付けなくても参照できます。

あえて、自身の変数にファイル名を付けて参照するには Me.変数名 のように Me を付けます。Me は自身のインスタンスを表しています。ただし標準モジュールには Me を付けられません。

Sheet1 のコード

Public パブリックシート As Integer

Sub 実行シート()
    ' 別のファイルの変数
    Module1.パブリック標準 = 1  ' 標準モジュールの変数を参照する
    パブリック標準 = 2          ' 標準モジュールの変数は、変数名だけでも参照できる

    ' 自身の変数
    パブリックシート = 3        ' 宣言したファイルの変数は、変数名だけで参照できる
    Me.パブリックシート = 4     ' 宣言したファイルの変数は、Me を付けても参照できる
    Sheet1.パブリックシート = 5 ' 宣言したファイル名でも参照できるが、通常は Me を付ける
End Sub

標準モジュール1 のコード

Public パブリック標準 As Integer

Sub 実行標準()
    ' 別のファイルの変数
    Sheet1.パブリックシート = 1 ' Sheet1 の変数を参照する
    パブリックシート = 2        ' エラー、ファイル名がないので参照できない

    ' 自身の変数
    パブリック標準 = 3          ' 宣言したファイルの変数は、変数名だけで参照できる
    Me.パブリック標準 = 4       ' エラー、標準モジュールに Me は使用できない
    Module1.パブリック標準 = 5  ' 宣言したファイル名でも参照できる
End Sub

いろいろな参照方法がありますが ファイル名.変数名 または Me.変数名 で参照するのがオススメです。Public 変数であることを意識できます。

注意点

定数や固定長文字列や配列や構造体などを Public 変数で宣言するには、標準モジュールに入力する必要があります。詳しくは下記の「その他のスコープ」をご覧ください。

同じ名前の Public 変数を複数のファイルに宣言できます。その時どのファイルに宣言された変数なのかを意識する必要があります。

' Sheet1 のコード
Public パブリック As Integer

Sub 実行()
    パブリック = 1         ' Sheet1 の変数、宣言していないときは標準モジュールの変数
    Module1.パブリック = 2 ' 標準モジュールの変数
End Sub
' 標準モジュール1 のコード
Public パブリック As Integer

Sub 実行()
    パブリック = 1        ' 標準モジュールの変数
    Sheet1.パブリック = 2 ' Sheet1 の変数
End Sub

混同しないためにも ファイル名.変数名Me.変数名 形式で参照するのをオススメします。

また同じファイル内でも Public と Dim や Private と Dim で同じ名前の変数を宣言できます。混同しないためにも同じ名前の変数は宣言しないようにします。

Public パブリック As Integer

Sub 実行()
    Dim パブリック As Integer

    パブリック = 1    ' ローカル変数
    Me.パブリック = 2 ' Public 変数
End Sub

変数の初期化

Public や Private の変数はマクロが終了しても値が残ります。続けてマクロを実行すると正常に動作しないことがあります。

このため、マクロを実行したら最初にすべての Public や Private の変数を初期化する必要があります。

Private プライベート変数 As Integer

Sub 実行()
    Call 初期化 ' すべての変数を初期化
    Call サブ   ' 1、再び実行しても 1
    Call サブ   ' 2、再び実行しても 2
End Sub

Sub 初期化()
    プライベート変数 = 0 ' 変数の数だけ初期化
End Sub

Sub サブ()
    プライベート変数 = プライベート変数 + 1 ' 呼ばれるたびにカウントアップ
    Debug.Print(プライベート変数)
End Sub

変数の数が多くなると初期化も大変になります。初期化を忘れることもあるかもしれません。簡単に初期化するには変数をクラスにまとめることです。

Private c As Class1

Sub 実行()
    Call 初期化 ' すべての変数を初期化
    Call サブ   ' 1、再び実行しても 1
    Call サブ   ' 2、再び実行しても 2
End Sub

Sub 初期化()
    Set c = New Class1 ' クラスの変数をすべて初期化
End Sub

Sub サブ()
    c.クラス変数 = c.クラス変数 + 1 ' 呼ばれるたびにカウントアップ
    Debug.Print(c.クラス変数)
End Sub

どれだけ変数が増えてもクラスをインスタンス化 Set c = New Class1 するだけで、その中の変数がすべて初期化されます。クラスは VBA 初心者には難しいので、慣れるまではクラスを使用しない方が簡単です。

Public、Private 関数

関数でも Public や Private の意味は変数と同じです。関数に Dim は使用できません。Public や Private 変数などの下に宣言します。

Sheet1 のコード

Sub 実行シート()
    ' 別ファイルの関数
    Call Module1.パブリック標準   ' 標準モジュールの関数を呼び出す
    Call パブリック標準           ' 標準モジュールの関数は、関数名だけでも呼び出せる

    ' 自身の関数
    Call パブリックシート         ' 宣言したファイルの関数は、関数名だけで呼び出せる
    Call Me.パブリックシート      ' 宣言したファイルの関数は、Me を付けても呼び出せる
    Call Sheet1.パブリックシート  ' 宣言したファイル名でも呼び出せるが、通常は Me を付ける
End Sub

Public Sub パブリックシート()

End Sub

Private Sub プライベートシート()

End Sub

標準モジュール1 のコード

Sub 実行標準()
    ' 別のファイルの関数
    Call Sheet1.パブリックシート  ' Sheet1 の関数を呼び出す
    Call パブリックシート         ' エラー、ファイル名がないので呼び出せない

    ' 自身の関数
    Call パブリック標準           ' 宣言したファイルの関数は、変数名だけで呼び出せる
    Call Me.パブリック標準        ' エラー、標準モジュールに Me は使用できない
    Call Module1.パブリック標準   ' 宣言したファイル名でも呼び出せる
End Sub

Public Sub パブリック標準()

End Sub

Private Sub プライベート標準()

End Sub

Public や Private を省略したときは Public 関数になります。つまり Public Sub 関数がマクロになります。

Sub 省略シート() ' Public になる

End Sub

変数と同様に混同しないためにも ファイル名.関数名Me.関数名 形式で呼び出すのをオススメします。

その他のスコープ

定数や固定長文字列や配列や構造体を Public で宣言するには、標準モジュールにする必要があります。Sheet1 やクラスには宣言できません。

' 標準モジュールのコード
Public Const 定数 As Integer = 1

Public 固定長 As String * 3 

Public 配列() As String

Public 構造体変数 As 構造体

Public Type 構造体
    a As Integer
End Type

' Sheet1 やクラスに宣言するとエラーになる

シートなどで宣言すると次のエラーが発生します。

まとめ

Public の変数はすべてのファイルから参照できるので便利に思いますが、なるべく狭い範囲のスコープを使用します。どこからでも参照できることは、逆にどこからでも値が変更され不具合の原因になります。デバッグする範囲が広がり修正が大変になります。

関数に引数を渡す方法を覚えると Public 変数で宣言していたものを Private 変数にできるようになります。

最初は Dim、次に Private、最後に Public といったように、できるだけ狭いスコープでコードが作成できないかを試します。