Excel VBA | 超初心者(Excel操作+マクロ体験):VBA基礎環境 – スコープ概念

Excel VBA VBA
スポンサーリンク

「スコープ」は“見える範囲”という発想でとらえる

VBAでいう「スコープ」は、ざっくり言うと
「この変数(やプロシージャ)は、どこから見える(使える)のかという“範囲”」です。

同じ名前の変数でも、書いた場所によって「ここでは使えるけど、あそこからは見えない」ということが起こります。
この“見える/見えない”のルールを知らないままコードを書くと、「さっきの変数がここで使えない」「別のところで同じ名前を使って壊れた」みたいな混乱が起きやすくなります。

だから、スコープの感覚を早めに持っておくと、
「この変数は、この中だけで完結させよう」
「これは全体で共有したいから、もう少し広い範囲に置こう」
と、設計の考え方が一段クリアになります。


まずは変数のスコープから入る

プロシージャの中だけで使える変数(ローカル変数)

一番よく使うのが、「その Sub / Function の中だけで有効な変数」です。
プロシージャの中で Dim した変数は、そのプロシージャの外からは見えません。

Option Explicit

Sub Sample1()

    Dim msg As String
    msg = "Sample1 からこんにちは"
    MsgBox msg

End Sub

Sub Sample2()

    MsgBox msg   ' ← ここではエラー(msg が見えない)

End Sub
VB

msg は Sample1 の中で Dim されています。
だから「Sample1 の中では使えるけれど、Sample2 からは存在しない扱い」になります。

ここで感じてほしいのは、
「変数は、宣言した“場所”によって、見える範囲が決まる」
ということです。

超初心者のうちは、
「基本は“その Sub の中だけで使う変数”として Dim する」
というスタイルをベースにすると、スコープで迷子になりにくくなります。

モジュールの先頭で宣言した変数(モジュールレベル変数)

次に、「同じモジュールの中の複数のプロシージャで共有したい変数」を考えます。
その場合は、モジュールの一番上(プロシージャの外)で Dim します。

Option Explicit

Dim counter As Long   ' モジュールレベル変数

Sub CountUp1()

    counter = counter + 1
    MsgBox "CountUp1: " & counter

End Sub

Sub CountUp2()

    counter = counter + 1
    MsgBox "CountUp2: " & counter

End Sub
VB

この場合、counter は「このモジュールの中にあるすべてのプロシージャから見える」変数になります。
CountUp1 を実行してから CountUp2 を実行すると、counter の値は引き継がれます。

・Sample1 の中で Dim した msg は Sample1 の中だけ
・モジュールの先頭で Dim した counter は、そのモジュールの Sub / Function から共通で見える

この違いが、「プロシージャレベル」と「モジュールレベル」のスコープの違いです。


Public / Private と「プロジェクト全体」のスコープ

Public 変数:ブック全体から見える変数

さらに一歩広げると、「このブックのどのモジュールからでも使える変数」が欲しくなることがあります。
そのときに使うのが Public です。

Option Explicit

Public UserName As String   ' プロジェクト全体から見える

Sub SetUserName()

    UserName = "山田"
    MsgBox "ユーザー名を設定しました"

End Sub
VB

別の標準モジュールからでも、UserName にアクセスできます。

Option Explicit

Sub ShowUserName()

    MsgBox "現在のユーザーは " & UserName & " さんです"

End Sub
VB

ここでは、
・UserName は「プロジェクト全体(このブックのすべてのモジュール)」から見える
という、最も広いスコープを持っています。

ただし、超初心者のうちから何でもかんでも Public にしてしまうと、
「どこからでも書き換えられてしまう危険なグローバル変数だらけ」になり、バグの温床になります。

なので、
「本当に全体で共有したいものだけ Public」
という意識を持っておくと、後々かなり楽になります。

Private 変数:モジュールの中だけに閉じ込める

モジュールレベル変数を Dim ではなく Private で宣言すると、
「そのモジュールの中だけで使える変数」という意味がより明確になります。

Option Explicit

Private totalCount As Long   ' このモジュールの中だけ

Sub AddCount()

    totalCount = totalCount + 1

End Sub

Sub ShowCount()

    MsgBox "合計回数: " & totalCount

End Sub
VB

別のモジュールから totalCount を参照しようとすると、コンパイルエラーになります。
「この変数は、このモジュールの中だけで完結させたい」という意図を、Private がはっきり表してくれます。

Dim でモジュール先頭に書いた場合も、既定では「そのモジュール内だけ」のスコープですが、
Private を付けると「意図的に閉じている」ことが読み手に伝わるので、設計としても分かりやすくなります。


プロシージャ(Sub / Function)にもスコープがある

Public Sub / Private Sub の違い

スコープの考え方は、変数だけでなくプロシージャにも適用されます。

Option Explicit

Public Sub PublicProc()

    MsgBox "どのモジュールからでも呼べる Sub です"

End Sub

Private Sub PrivateProc()

    MsgBox "このモジュールの中からしか呼べない Sub です"

End Sub
VB

PublicProc は、他のモジュールからも呼び出せます。

Sub CallPublic()

    PublicProc   ' OK

End Sub
VB

一方、PrivateProc は同じモジュールの中からしか呼べません。
別モジュールから呼ぼうとすると、「定義されていません」というエラーになります。

ここでもキーワードは
「どこから見えるようにしたいか」=スコープ
です。

・外部から呼んでほしい窓口的な Sub は Public
・内部でだけ使う“裏方”の Sub は Private

という分け方を意識すると、コードの見通しがかなり良くなります。


スコープを体感するための小さな例題

同じ名前の変数でも“別物”になる例

次のコードを見てください。

Option Explicit

Sub Proc1()

    Dim x As Long
    x = 10
    MsgBox "Proc1 の x = " & x

End Sub

Sub Proc2()

    Dim x As Long
    x = 20
    MsgBox "Proc2 の x = " & x

End Sub
VB

どちらも x という名前ですが、
・Proc1 の中の x
・Proc2 の中の x
は、完全に別の変数です。

Proc1 を実行すれば「10」、Proc2 を実行すれば「20」が表示されます。
お互いの x は見えませんし、影響もしません。

ここで感じてほしいのは、
「名前が同じでも、スコープが違えば別物」
ということです。

モジュールレベル変数とローカル変数の違いを感じる

次に、モジュールレベル変数とローカル変数を混ぜた例です。

Option Explicit

Dim count As Long   ' モジュールレベル

Sub IncLocal()

    Dim count As Long   ' ローカル
    count = count + 1
    MsgBox "IncLocal の count = " & count

End Sub

Sub IncModule()

    count = count + 1
    MsgBox "IncModule の count = " & count

End Sub
VB

IncLocal の中で Dim した count は、その Sub の中だけのローカル変数です。
モジュール先頭の count とは別物です。

・IncLocal を何度実行しても、毎回ローカル変数 count は 0 からスタートして 1 になります。
・IncModule を実行すると、モジュールレベルの count が 1, 2, 3… と増えていきます。

「同じ名前でも、どこで宣言したかによって、どの count を指しているかが変わる」
これがスコープの具体的な“効き方”です。


超初心者向けの実践的なスコープの使い方ルール

最後に、超初心者の段階で意識しておくと楽になる“ゆるいルール”をまとめます。

・まずは「変数は基本、Sub / Function の中で Dim して、その中だけで使う」と決めてしまう。
・どうしても複数のプロシージャで共有したい値が出てきたら、モジュール先頭に Dim(または Private)して「このモジュールの中だけで共有」にとどめる。
・Public で全体共有するのは、「本当に全体から見えてほしいもの」に限る。

このくらいの意識でも、
「どこからでも何でも触れる“野ざらし状態”」からは一気に卒業できます。

スコープは、いきなり完璧に覚える必要はありません。
ただ、「変数やプロシージャには“見える範囲”があるんだ」という感覚だけ持っておくと、
コードを書きながら自然と「ここは閉じておこう」「ここは窓口にしよう」という発想が育っていきます。

タイトルとURLをコピーしました