🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA の GoTo — ラベルへのジャンプと、たいてい使うべきでない理由

|

Excel VBA の GoTo — ラベルへのジャンプと、たいてい使うべきでない理由

TL;DR — GoTo label は、同じ プロシージャの中で label: と印を付けた行へ、条件なしで実行を飛ばし ます。現代の VBA でこれがまだ居場所を持つ場面はちょうど一つ、エラー処理のための On Error GoTo です。そ れ以外のすべて — ループ、飛ばし、分岐 — では、ジャンプは構造化された道具(If、Exit For、Exit Sub、 Do)よりも追いにくく、ループの内や外へ飛ぶとループを静かに壊します。古いコードを読めるように構文は覚え、 新しいコードを書くときは構造化された書き方に手を伸ばしましょう。

Sub GoToBasics()
    Dim x As Long
    x = 5
    If x > 0 Then GoTo Positive

    Debug.Print "zero or negative"
    Exit Sub                 ' 下のラベルへ落ち込む前に止める

Positive:                    ' ラベル - 名前のあとにコロン
    Debug.Print "positive"
End Sub

GoTo は、存在するなかで最も古い制御フローの道具です。名前を付けたラベルへ、無条件に、あなたが選んだ一方向 へ実行を移します。VBA は今もこれをサポートしており、現代的な機能の一つ — On Error GoTo — はこの上に築か れています。ですが普通のフローでは、ジャンプは上から下へは読めないコードを作ります。だからこそ、新しいコー ドの GoTo はほとんどすべて、代わりに Exit か If であるべきなのです。

この記事で学べること

  • ラベルとジャンプの構文 — ラベルの書き方と、GoTo がそこへ届く仕組み
  • GoTo が今日でも本当に居場所を持つ唯一の場面 — On Error GoTo によるエラー処理
  • ループの 内 や 外 へ飛ぶと、なぜループカウンターが壊れ、仕事が中途半端に残るのか
  • VBA にない Continue をまねるために GoTo がどう誤用されるか、そしてきれいな代替手段
  • 別のプロシージャのラベルへ GoTo できない理由
  • どんなジャンプよりも読みやすい、構造化された代替手段

考え方の軸:無条件・一方通行のジャンプ

ラベル は、名前のあとにコロンを付けて一行に単独で置いたものです。GoTo label は、そこへ実行をまっすぐ 移します。

GoTo CleanUp     ' CleanUp: と印を付けた行へ前方(または後方)へ飛ぶ
' ... ここにある行はすべて飛ばされる ...
CleanUp:         ' <-- 実行はここから再開する

二つの性質が、GoTo を同じだけ強力で危険なものにしています。それは 無条件 です — それ自体は常に飛ぶの で、分岐させるには If で包む必要があります — そして、跡を残さない 一方通行 の移動です。制御がどこから 来たかを示すものは何もないので、コードを追う読み手は、ラベルに着地しうるすべての GoTo を見つけるためにプ ロシージャ全体を走査しなければなりません。Exit For のような構造化された文は、制御がどこへ行くか(Next のすぐ先)を正確に教えてくれます。GoTo はどこからでも来られます。その違いこそが、GoTo に反対する論拠の すべてです。

GoTo が居場所を持つ唯一の場面:On Error GoTo

ここに例外があり、それは本物です。VBA のエラー処理は GoTo の上に築かれて います。On Error GoTo は、実 行時エラーが起きたときにどのラベルへ飛ぶかを VBA に伝えます。これは慣用的で、期待されており、この言語には構 造化された代替がありません。

Sub SafeOpen()
    On Error GoTo Failed
    Workbooks.Open "C:\reports\data.xlsx"
    Exit Sub

Failed:
    MsgBox "Could not open the file."
End Sub

Failed: ラベルの前にある Exit Sub に注目してください — これがないと、何も問題が起きていなくても、通常の 経路がエラーハンドラーへ 落ち込んで しまいます。この落ち込みは、GoTo とラベル付きコードにまつわる古典的 なバグで、エラーハンドラーに限らずすべてのラベルに当てはまります。仕組みの全体は VBA On Error を参照してください。On Error の外では、GoTo は道具ではなく警告サ インです。

落とし穴:ループの内や外へ飛ぶ

GoTo でできる最悪のことは、For や Do ループの境界をまたいで飛ぶことです。GoTo でループの 外 へ飛 ぶと、ループの通常の出口を素通りします — カウンターは保持していた値のまま残され、ループが終わらせるはずだっ たことは飛ばされます。ループの途中へ 中に 飛び込むと、結果はもっと悪くなります。カウンターが一度も初期化 されていないので、動作は未定義です。

' これをしてはいけない - GoTo でループの外へ飛ぶ
For i = 1 To 100
    If Cells(i, 1).Value = "X" Then GoTo AfterLoop   ' ループのクリーンな出口を飛ばす
Next i
AfterLoop:

上のコードはたまたま動きますが、正直な書き方は Exit For で、これはループを本来のドアから出て、意図をはっ きりさせます。「ループの外へ飛ぶ」はどれも Exit For か Exit Do と書いたほうがよ く、「今すぐプロシージャを出る」はどれも Exit Sub と書いたほうがよいのです。これらは自分が出る構造を名指 しし、制御を予測できる場所に着地させます — GoTo はそのどちらもしません。

GoTo で Continue をまねる — そしてきれいな代替手段

VBA には次のループの繰り返しへ飛ぶ Continue 文がないので、古いコードはしばしば、Next の直前にラベルを置 いてそこへ飛ぶことで、それを模倣します。

' GoTo で「continue」するやり方 - 動くが、これはジャンプ
For i = 1 To n
    If Cells(i, 1).Value = "" Then GoTo NextRow
    ' ... 行を処理する ...
NextRow:
Next i

これは動きますが、ループを理解するために読み手をあちこち飛び回らせます。構造化された書き方は、単に条件を裏 返して、飛ばされる繰り返しが何もせず Next へ抜け落ちるようにします。

' 構造化されたやり方 - ラベルなし、ジャンプなし
For i = 1 To n
    If Cells(i, 1).Value <> "" Then
        ' ... 行を処理する ...
    End If
Next i

動きは同じで、まっすぐ下へ読めます。飛ばす条件が一つの判定なら、If が常に勝ちます。Next の前にラベルを 置くパターンは、飛ばす処理が一つの If には込み入りすぎている、まれな場合のために取っておきましょう — そし てその場合でも、本体を専用のプロシージャに分けることを検討してください。

プロシージャをまたいで GoTo はできない

ラベルは、それが存在するプロシージャに閉じています。GoTo が飛べるのは 同じ Sub または Function の中のラベルだけで、あるプロシージャから別のプロシージャへは飛べません(VBA はコンパイルエラー Label not defined を出します)。別のプロシージャへ飛び込みたくなったなら、あなたが本当にしたいのはそれを 呼ぶ こと — MyCleanup あるいは Call MyCleanup — であり、これはあとで制御をあなたに返してくれます。まさ にジャンプにはできないことです。この制限は一つの美点です。すべてのジャンプを、読める一つの単位の中に閉じ込 めてくれます。

ジャンプが本当に一番ましな選択肢になるとき

正直に言えば、一つだけ譲るべき点があります。深くネストしたループ から抜けることは、外側のループの先にあ るラベルへの GoTo が代替手段よりきれいになりうる、唯一の制御フローの場面です。VBA は一度に一段より多くの ループを Exit できないからです。それでもここでさえ、ネストしたループを Function に切り出して Exit Function を使うほうが、たいていは分かりやすいのです。目安はこうです。GoTo に手を伸ばしていて、それ が On Error GoTo でないなら、いったん止まって、Exit や If、あるいは小さなヘルパープロシージャがジャン プなしで同じことを言えないか、自問してください。百回のうち九十九回は、言えます。

ExcelMaster の活用

GoTo は書くのは簡単で読むのは難しく、これはまさに、半年後には誰にも保守できないマクロを生む組み合わせで す。噛みついてくる間違いは二つ、手前の Exit Sub が抜けているときにラベルへ落ち込むことと、カウンターと仕 事を未定義の状態に残すループ境界をまたいだジャンプです。

ExcelMaster は、上から下へ読めるフローを書 きます。ループが止まるべきところには Exit For、プロシージャが切り上げるべきところにはガード節、そして On Error GoTo は本来の居場所 — エラー処理 — だけに、通常の経路をハンドラーの外に保つ Exit Sub を添え て。ブックとコードはあなたの手元に残ります。

よくある質問

VBA の GoTo は何をしますか?

GoTo label は、同じプロシージャの中で label: と印を付けた行へ、無条件に実行を移します。ラベルは、名前の あとにコロンを付けて一行に単独で置いたものです。GoTo は常に飛ぶので、分岐させるには If で包む必要があり ます。たとえば If x < 0 Then GoTo Negative のように。実行はそこから、ラベル以降を続けます。

VBA で GoTo は悪い書き方ですか?

普通の制御フローでは、はい — ジャンプは構造化された文よりも追いにくく、ループの内や外へ飛ぶとループカウンタ ーを壊すことがあります。重要な例外は On Error GoTo で、これは実行時エラーをハンドラーへ導く、慣用的で期待 されるやり方です。古いコードを読むために GoTo を覚え、新しいコードを書くときは Exit、If、Do ループ を好みましょう。

GoTo のためのラベルはどう書きますか?

名前のあとにコロンを付けて一行に単独で置きます。たとえば CleanUp: のように。そして GoTo CleanUp でそこ へ飛びます。ラベルは大文字小文字を区別せず、プロシージャに閉じています。プロシージャの末尾にあるラベルの前 には、必ず Exit Sub を置いてください。さもないと、ジャンプするつもりがなくても、通常の経路がラベル付きの コードへ落ち込んでしまいます。

GoTo は別の Sub や Function へ飛べますか?

いいえ。GoTo が届けるのは同じプロシージャの中のラベルだけで、別の Sub や Function へ飛び込むのはコン パイルエラーです。別のプロシージャのコードを実行するには、名前で呼びます — 呼び出しは終わるとあなたに制御を 返します。これはたいてい欲しいことであり、ジャンプには決してできないことです。

GoTo を使わずにループを抜けるには?

For ループには Exit For を、Do ループには Exit Do を使います — どちらもループを本来の出口から出て、 その次の行から続きます。ループを抜けるのではなく繰り返しを一回だけ飛ばすには、本体を If で包んで、飛ばす 周回が何もしないようにします。全体像は VBA Exit For を参照してください。

検証環境

検証環境: Excel 365 (Windows 11)、VBA 7.1 — 最終確認 2026-09-24。

関連ガイド: VBA Exit For · VBA End · VBA On Error · VBA For Loop · VBA If Then Else