Skip Or Break In A Range Loop
Fast recall
Quick revision
Core answer
Practical understanding of Range Over Slice Map.
Repeating a definition without saying when to use it.
Give one trade-off and say how you would test it.
Interview-ready guide
Interview answer
The two keywords cover the single-loop cases:
for _, v := range items {
if skip(v) {
continue // next iteration
}
if fatal(v) {
break // exit the loop entirely
}
process(v)
}The case the keywords don't cover: breaking out of a NESTED loop from the inner body. That's what labels are for — the one labeled-statement use that survives modern Go:
outer:
for _, row := range matrix {
for _, cell := range row {
if cell == target {
break outer // exits BOTH loops
}
}
}Note what Go deliberately lacks: labeled continue. goto exists (and is occasionally the clean answer for error-cleanup ladders), but the loop-control set is continue, break, and labeled break — no labeled continue, which the designers considered unnecessary after the labeled-break case.
In idiomatic Go, deep nesting with labels is rare — the culture prefers early returns and small functions, so a labeled break usually signals a loop body that wants to be its own function returning an error/flag. Labels are the honest tool when extraction would be more ceremony; extraction is the default when it reads better.
Skip Or Break In A Range Loop
Direct Answer
continue skips to the next iteration; break exits the loop. Labels break out of NESTED loops — Go has no labeled continue.
Deep Dive & Architecture
Labels are the feature people reach for last and should reach for earlier. The semantics: a label marks a statement; break LABEL exits the labeled loop regardless of nesting depth. Without it, break binds to the innermost loop only — and the boolean-flag-across-nested-loops pattern is what labels replace:
// the pattern labels replace
found := false
for _, row := range matrix {
for _, cell := range row {
if cell == target {
found = true
break // exits inner only — outer keeps scanning
}
}
if found { break }
}
versus the labeled form, which says exactly what it means:
usersByCity: // find the first user in any city matching a prefix
outer:
for city, users := range directory {
for _, u := range users {
if strings.HasPrefix(u.Name, "inv") {
fmt.Println("found:", city, u.Name)
break outer // directory search done — stop scanning everything
}
}
}
Why no labeled continue? The Go spec discussions concluded it added a second axis of control flow for a case that extracting a function handles better — continue-to-outer-label is almost always a sign the inner loop wants to BE a function returning 'found it or not.' The tool set (continue, break, labeled break, goto for cleanup ladders) covers the real cases; the missing piece pushes you toward better structure.
goto's one surviving idiomatic use is the same family: error-ladder cleanup in C-era code translated to Go — forward goto a cleanup block, fall-through otherwise. Every other goto in review is a refactor request.
Common Mistakes & Pitfalls
Repeating a definition without saying when to use it.
Check your understanding
Answer these without looking back at the article.
- What is Range Over Slice Map, and when would you use it?
- When would you use Range Over Slice Map in a real project?
- How would you compare Range Over Slice Map with an alternative?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.