INDEX
continueの概要
| どの条件にも一致しない時の処理を実行するGoの予約語 | ||
|
continue 概要 continueは、ループ(繰り返し処理)の現在のブロック内における残りの命令コードをすべてスキップし、ループの条件評価式または次のインクリメント処理へ直接制御を移すために使用します。 |
||
|
continueの考え方をイメージで理解

基本的なcontinueの使い方(特定条件のフィルタリング)
最も典型的な用途は、特定の条件を満たす要素(または満たさない要素)に対する処理をスキップする「ガード節(Guard Clause)」としての実装です。これにより、コードのインデントを深くせずに処理を記述できます。
package main
import "fmt"
func main() {
// 1から10までの整数ループ
for i := 1; i <= 10; i++ {
if i%2 != 0 {
continue // 奇数の場合はこれ以降のコードを実行せず、i++(次の周)へジャンプ
}
// 偶数の場合のみ実行される
fmt.Println("偶数:", i)
}
}
構造解説:
iが奇数の場合(i%2 != 0)、ランタイムはcontinue命令に到達した瞬間に、それより下に配置されているfmt.Printlnを無視します。- その後、
forループの更新式であるi++が実行され、次の条件検証へと進みます。結果として、不要なデータを弾くフィルタリングが実現します。
実行結果:
偶数: 2 偶数: 4 偶数: 6 偶数: 8 偶数: 10
特定の条件で処理をスキップ(中間状態の離脱判定)
ループ処理の途中で特定の例外値やエラー状態を検知した際、その要素のみ処理を中断して全体のループを継続させたい場合に使用します。
package main
import "fmt"
func main() {
for i := 1; i <= 5; i++ {
if i == 3 {
fmt.Println("【警告】インデックス3の処理はスキップします")
continue
}
fmt.Println("データ処理を実行中:", i)
}
}
構造解説:
i == 3の条件に合致したタイミングでのみ、「【警告】...」のログが出力され、continueによって関数全体の終了やループ全体の破壊(break)を行うことなく、4回目のループへ処理が引き継がれます。
実行結果:
データ処理を実行中: 1 データ処理を実行中: 2 【警告】インデックス3の処理はスキップします データ処理を実行中: 4 データ処理を実行中: 5
ネストしたループにおけるcontinueの挙動(内側ループへの限定作用)
for ループが多重に組み合わされている(ネストしている)場合、修飾子のない標準の continue は、自身が直接所属している最も内側のループに対してのみスキップ効果を及ぼします。
package main
import "fmt"
func main() {
for i := 1; i <= 3; i++ {
for j := 1; j <= 3; j++ {
if j == 2 {
continue // 最も内側にある「j」のループの次(j++)へ進む
}
fmt.Printf("i:%d, j:%d\n", i, j)
}
}
}
構造解説:
- 内側のループで
j == 2になると、continueによってその周のfmt.Printfがスキップされますが、外側のループ(iのカウンタ)の実行フローには一切干渉しません。したがって、jのループが 3 まで回りきった後は通常通り次のiの処理が行われます。
実行結果:
i:1, j:1 i:1, j:3 i:2, j:1 i:2, j:3 i:3, j:1 i:3, j:3
ラベル付きcontinue(外側ループの制御と多重ループ脱出)
ネストしたループにおいて、内側のループ内の条件分岐から「外側のループの次の周」へ一気に制御を飛ばしたい場合、ターゲットとなるループの直前に識別子(ラベル)を定義し、continue ラベル名 の形式で呼び出します。
package main
import "fmt"
func main() {
// 外側のループに対して「MainIterator」というラベルを定義
MainIterator:
for i := 1; i <= 3; i++ {
for j := 1; j <= 3; j++ {
if j == 2 {
// 内側のループを破棄し、外側の「i」の次の反復ステップへ直接ジャンプ
continue MainIterator
}
fmt.Printf("確定要素 -> i:%d, j:%d\n", i, j)
}
}
}
構造解説:
j == 2に到達した瞬間、内側のjの残り処理(j=3の回など)は完全に破棄され、制御は直ちにMainIteratorラベルが指す外側ループのi++へジャンプします。- これは、二次元配列や行列の探索において「特定の条件を満たさない行を見つけた時点で、その行の評価を打ち切って次の行の検証に移る」といったアルゴリズムを実装する際に極めて強力な手法となります。
実行結果:
確定要素 -> i:1, j:1 確定要素 -> i:2, j:1 確定要素 -> i:3, j:1
学術的・設計的注意点
- 更新式(インクリメント)の評価位置と無限ループのリスク:
forループを手動の条件式(C言語スタイルのfor 状態; 条件; 更新ではなく、for 条件 { ... }のようなwhileループ相当の実装)で回している場合、continueを呼び出す位置に最大級の注意が必要です。もしcontinueよりも後ろの行にカウンタの更新式(i++など)を記述していると、更新処理自体が永久にスキップされ続けるため、条件式が常にtrueのまま固定されて深刻な無限ループ(CPUリソースの枯渇)を誘発します。 - スパゲッティコード化への警戒(ラベルのスコープ制限): ラベル付き
continueは非常に強力ですが、濫用すると構造化プログラミングの原則を歪め、処理の追跡が不可能な「スパゲッティコード」を生成する要因になります。Go言語のコンパイラは、continueに指定するラベルが「同一関数内の自身を内包するforループ」に付与されたものであることを厳格に要求するため、全く関係のないコードブロックへジャンプするような不正な操作はコンパイル段階で完全に排除されます。
よくある質問(FAQ)
- Q: continueとbreakの明確な使い分けの基準は何ですか?
- A: ループの「継続」か「完全終了」かが基準です。
continue:問題のある要素や特定の条件だけを除外(パス)し、残りの要素の処理は最後まで続けたい場合に使用します。break:目的のデータを発見した場合や、エラーによってこれ以上イテレーションを続ける意味が喪失した瞬間に、ループ空間そのものから即時脱出したい場合に使用します。
- Q: continueを使わずに、if-else文だけで同様の処理を書くべきですか?
- A: スキップする条件が単純であれば、
continue(ガード節)を使用する方が推奨されます。if-elseの中にすべての正常処理をネストさせると、条件が増えるたびにコードの階層が右側へ深く進んでしまい(ネストの階層化)、可読性が著しく低下するためです。「異常値はcontinueで即座に弾き、メイン処理は常に一番浅いインデントレベルに保つ」のがクリーンコードの定石です。 - Q: range構文を用いたスライスやマップのループでもcontinueは同じように動作しますか?
- A: まったく同じように動作します。
rangeループ内でcontinueが実行された場合も、現在の要素の処理を打ち切り、内部のイテレータが次の要素(次のインデックスやキー)を自動的にロードして、ループの先頭から処理が再開されます。
まとめ
continueは、ループの現在のイテレーションを途中で打ち切り、次の反復サイクルへ強制的に遷移させるための制御用キーワード。- ガード節として適切に配置することで、複雑な条件分岐によるインデントの深化を防ぎ、コードの直線的な可読性を高める。
- 多重ネスト構造の中では、標準時は直近の内側ループにのみ作用し、ラベル明示時は指定された外側の親ループまで制御ラインをジャンプさせることが可能。
- 手動制御ループにおいては更新式の配置漏れによる無限ループの発生リスクに留意し、コードの複雑性を管理可能な範囲に留める設計が必要となる。