VBAのGoToは足りない制御構文を補うために使う
VBAでGoToを避けるべき場面と、使ったほうが素直になる場面を分けて考える
Copyright © 2026 LWP 山中 一弘
本資料は、出典を明記いただければ、商用・非商用を問わず、ご自由に複製・改変・再配布していただけます。なお、著作権表示は改変せず、そのまま記載してご利用くださいますようお願いいたします。
記事要約
VBAを学ぶと、「GoToを使うコードは悪い」「GoToとラベルは忘れたほうがよい」という説明に出会うことがあります。たしかに、GoToで処理全体の流れを組み立てる書き方は、読みづらく、保守しづらいコードになりやすいものです。
しかし、そこから「VBAではGoToを一切使ってはいけない」と考えると、別の問題が起きます。VBAには、多重ループから一気に抜ける構文、ループ先頭へ戻るcontinue相当の構文、例外処理を柔軟に組み立てる構文が十分にはありません。その不足を無理にフラグ変数や不自然なループで補うと、GoToを使うより読みにくいコードになります。
この記事では、GoToを「制御構造を作る道具」として使う場合と、「足りない制御構文を補う道具」として使う場合を分けます。そのうえで、VBAでは後者の用途に限定すれば、GoToはコードをシンプルにするための実用的な選択肢になることを整理します。
本記事の対象とゴール
想定読者
VBAでGoToを使ってよいのか迷っている人
「GoToは有害」という説明を聞いたが、VBAの実務コードで納得できていない人
多重ループの脱出、共通終了処理、エラー処理、リトライ処理をVBAでどう書くか考えている人
コーディング規約と実務上の読みやすさの間で判断軸を持ちたい人
本記事で得られること
GoToを避けるべき使い方と、使ってよい使い方を分けて判断できます。
VBAでGoToが有効になる代表的な場面を整理できます。
多重ループ脱出や共通終了処理を、フラグ変数に頼りすぎずに書く考え方を得られます。
本記事で扱わないこと
GoToを多用した古いBASIC風、FORTRAN風、COBOL風コードを推奨すること
会社や現場のコーディング規約を無視すること
すべての言語でGoToを同じように扱うこと
先に結論
VBAで避けるべきなのは、GoToそのものではありません。
避けるべきなのは、If、For、Do、Sub、Functionなどで普通に書ける制御構造を、GoToとラベルだけで組み立てることです。
一方で、VBAに足りない制御構文を補うために、出口を明確にしたGoToを使うのは合理的です。たとえば、多重ループからの一括脱出、共通終了処理、エラー処理、リトライ、continue相当の処理では、GoToを使ったほうが素直になる場面があります。
判断基準は、「GoToを使っているか」ではありません。
判断基準は、そのGoToがコードの構造を壊しているか、それとも構造化されたコードの不足部分を補っているかです。
第1章 GoTo有害論は何を問題にしていたのか
GoToが嫌われる理由は、歴史的な背景を抜きにすると分かりにくくなります。
古い環境では、現在のような構造化された書き方が十分に整っていませんでした。処理の分岐、繰り返し、途中脱出を、ラベルとジャンプでつなぐことが多く、その結果として、どこから来てどこへ行くのか追いづらいコードが生まれました。
この文脈での「GoToは有害」は、GoToを使うことで処理の秩序が失われることへの批判です。つまり、GoToを使ってプログラム全体の制御構造を作ってしまうことが問題でした。
現代のVBAコードは、通常、Sub、Function、If、For、Do、Select Caseなどの構文を前提に書きます。構造化されたコードが先にあり、その中で一部の足りない出口をGoToで補うなら、古い時代の問題とは意味が変わります。
第2章 GoToには2種類の使い方がある
GoToの使い方は、次の2つに分けて考えると整理しやすくなります。
1つ目は、制御構造をGoToで作る使い方です。
たとえば、通常のIfやForで書ける処理を、ラベルとGoToだけでつなぐ書き方です。これは、現在のVBAでは避けるべきです。処理のまとまりが見えにくくなり、後から読む人が制御の流れを追いづらくなります。
2つ目は、制御構文の足りないところをGoToで補う使い方です。
たとえば、二重ループの内側で目的の値を見つけたとき、外側のループも含めて一気に抜けたい場合です。VBAのExit Forは、その場のForを1つ抜けるだけです。外側のForまで抜ける構文はありません。この不足を補うために、明確な出口ラベルへGoToする使い方は、制御構造を壊すものではありません。
この記事で推奨するのは、後者だけです。
第3章 VBAでGoToが有効になる代表場面
VBAでGoToを検討する場面は、主に次の4つです。
1つ目は、共通終了処理です。
処理の途中で終了する条件が複数ある場合、Exit Subをあちこちに置くと出口が増えます。終了時にログ、後始末、画面更新の復帰、オブジェクト解放などを行うなら、出口を1つに寄せたほうが安全です。
2つ目は、多重ループからの一括脱出です。
VBAには、二重、三重のループを一気に抜ける専用構文がありません。フラグ変数で外側のループへ脱出を伝える方法もありますが、脱出のためだけの状態が増え、かえって読みにくくなることがあります。
3つ目は、リトライ処理です。
一時的なエラーや待機後の再試行を行う場合、処理の再実行位置を明確なラベルにしておくと、リトライの流れを短く書けることがあります。
4つ目は、エラー処理とログの共通化です。
VBAには On Error GoTo があり、言語仕様としてエラー時のジャンプを使います。エラー処理を出口に集約するなら、GoTo系の制御を完全に排除するより、出口とエラー処理の役割を分けて明確にするほうが実務的です。
第4章 多重ループの脱出はGoToのよい例である
次のような二次元配列の検索を考えます。
For i = 1 To rowCount For j = 1 To colCount If values(i, j) = target Then ' ここで両方のループを抜けたい End If Next jNext iVBAの Exit For では、内側のForしか抜けられません。外側のForも抜けるには、フラグ変数を使う、外側をDoで包む、最後までループを回し切る、検索処理だけを別関数にする、などの方法が考えられます。
しかし、どれも常に自然とは限りません。
最後までループを回し切る方法は、見つけた後も不要な処理を続けます。データが大きい場合は無駄です。
フラグ変数を使う方法は、脱出制御のためだけの変数が増えます。読む側は、検索条件だけでなく、脱出状態の管理も追う必要があります。
検索処理だけを別関数にする方法は、検索という意味のある単位なら有効です。しかし、後続処理で i と j をそのまま使うためだけに関数を分けるなら、関数分割の意味が弱くなります。関数は、共通の出口を作るためではなく、意味のある処理単位で分けるべきです。
この場合は、次のように出口ラベルを明確にしたほうが読みやすくなります。
Dim foundRow As LongDim foundCol As LongDim found As BooleanFor i = 1 To rowCount For j = 1 To colCount If values(i, j) = target Then foundRow = i foundCol = j found = True GoTo break00 End If Next jNext ibreak00:If found Then ' foundRow と foundCol を使った後続処理Else ' 見つからなかった場合の処理End IfこのGoToは、処理全体をラベルで組み立てているわけではありません。二重ループに足りない「外側までまとめて抜ける構文」を補っています。
第5章 共通終了処理では出口を1つに寄せる
アーリーリターンは、短い処理では読みやすい方法です。条件を満たさないときにすぐ抜けることで、ネストを浅くできます。
ただし、終了時に必ず行いたい処理がある場合は注意が必要です。途中にExit SubやExit Functionが複数あると、後始末やログの呼び忘れが起きやすくなります。
VBAでは、次のように出口を exit00 に寄せる形が実務的です。
Sub Sample() On Error GoTo err00 If Not CanRun() Then GoTo exit00 Application.ScreenUpdating = False ' 主処理exit00: Application.ScreenUpdating = True Exit Suberr00: ' エラー内容を記録する Resume exit00End Subここで重要なのは、ラベル名に役割を持たせることです。
exit00 は正常終了も異常終了も含めた共通出口です。err00 はエラー処理です。このようにラベルの用途を限定すれば、GoToは読み手にとって制御の目印になります。
第6章 GoToを使わないための工夫が悪手になることもある
GoToを避けるために、常に別の構文へ置き換えればよいわけではありません。
たとえば、多重ループ脱出を避けるために、フラグ変数を増やすことがあります。
Dim isBreak As BooleanFor i = 1 To rowCount For j = 1 To colCount If values(i, j) = target Then isBreak = True Exit For End If Next j If isBreak Then Exit ForNext iこの書き方は動きます。しかし、読む側は isBreak が何のためにあるのかを追う必要があります。ループが深くなったり、条件が増えたりすると、脱出制御のための変数が本文の意味を邪魔します。
GoToを使わないために、Doループを重ねる方法もあります。
Do For i = 1 To rowCount For j = 1 To colCount If values(i, j) = target Then Exit Do End If Next j Next i Exit DoLoopこれも動かすことはできます。しかし、検索処理を表すためにDoを使っているわけではありません。脱出の都合で構文をひねっています。
コードは、禁止事項を守るために読みにくくするものではありません。目的は、GoToを消すことではなく、意図した処理を簡潔に読みやすく書くことです。
第7章 初学者向けの禁止と実務の判断は分ける
初学者に対して、「まずGoToを使わずに書いてみる」と指導することは有効です。
理由は、構造化された書き方を先に身につける必要があるからです。If、For、Do、Sub、Functionで考える型を覚える前にGoToを使うと、処理のまとまりを作る練習になりません。
しかし、ある程度コードを書けるようになった後は、次の段階へ進む必要があります。
それは、「GoToを使わないコード」ではなく、「よいコード」を書く段階です。
VBAでは、よいコードを書くためにGoToを使う場面があります。特に、言語側に専用構文がない出口処理では、GoToのほうが素直です。
教育上の一時的な禁止と、実務上の設計判断を混同してはいけません。
第8章 GoToを使うときの実務ルール
VBAでGoToを使うなら、次のルールを置くと安全です。
1つ目は、ラベルの役割を限定することです。
exit00、err00、break00、retry00 のように、ラベル名で用途が分かるようにします。意味のないラベル名や、あちこちから飛び込むラベルは避けます。
2つ目は、前方ジャンプを基本にすることです。
処理を戻すジャンプは、リトライなどの用途に限定します。通常の処理を上下に行き来させると、読みづらくなります。
3つ目は、構造化された処理の中だけで使うことです。
GoToでIfやForの代わりを作るのではありません。IfやForで書かれた処理の、足りない出口だけを補います。
4つ目は、規約がある場合は規約を優先することです。
現場のコーディング規約でGoToが禁止されているなら、その制約の中で書く必要があります。ただし、なぜ読みにくくなるのか、どの代替案を採るのかは明確にしておくべきです。
第9章 画像と参照リンクから読み取ったこと
元のまとめには、本文投稿のほかにX/Twitterの画像リンクが含まれていました。
画像リンクとして確認できたのは、@Hiro_SysOp の投稿に付いた2枚の画像と、@hoehoe1234 の投稿に付いた1枚の画像です。今回の取得環境では、Posfie/Togetter本文のHTMLに画像本体URLは含まれておらず、X/Twitter写真ページと埋め込み取得エンドポイントからも画像メタデータを取得できませんでした。
そのため、画像内の文字やコードは直接判読できていません。記事本文では、画像からの推測は入れず、投稿本文とリンク先記事から読み取れる論点だけを使っています。
本文投稿から再現できるコード素材としては、二次元配列検索の例がありました。この記事では、その例をVBAとして実行しやすい形に整え、GoTo break00 による多重ループ脱出の例として再構成しました。
また、参照リンクとして、GoTo有害論のタイトルや構造化プログラミングの文脈に触れる記事が示されていました。この記事では、それらを「GoToそのものが目的ではなく、よいプログラムを書くための歴史的な議論がある」という背景整理として扱っています。
第10章 まとめ
VBAでGoToを使うべきかどうかは、単純な禁止・許可では判断できません。
GoToで制御構造そのものを作るなら、避けるべきです。現在のVBAでは、If、For、Do、Sub、Functionなどの構文を使って、処理のまとまりを作るべきです。
しかし、VBAに足りない制御構文を補うためなら、GoToは有効です。
多重ループからの脱出、共通終了処理、エラー処理、リトライ、continue相当の処理では、GoToを使うことでコードが短く、読みやすく、安全になる場合があります。
大切なのは、GoToを排除することではありません。
大切なのは、コードを簡潔に、意図が分かる形で、保守しやすく書くことです。その目的に合うなら、VBAではGoToを正しく使えばよいのです。
出典メモ
元Togetter URL: https://togetter.com/li/1845696
正規Posfie URL: https://posfie.com/@hoehoe1234/p/z1LDKgN
取得日: 2026-06-11
主な素材投稿者: @hoehoe1234、@Hiro_SysOp、@blacklist_ryu、@TaniponVBA
参考リンク: https://postd.cc/programming-myths/
参考リンク: https://monoist.itmedia.co.jp/mn/articles/1008/17/news092.html
画像確認: X/Twitter写真ページ3件を確認対象とし、HTML取得、埋め込み取得エンドポイント、Playwrightによる公開表示確認を試した。Playwrightではログイン/アカウント作成導線のみ表示され、現在の取得環境では画像本体URLと画像メタデータを取得できなかった。画像内コードや文字は未判読として扱い、本文には推測を入れていない。
本文への反映: 投稿本文の要点を長文転載せずに論点化し、二次元配列検索の例をVBAコードとして再構成した。
