Go's One Loop to Rule Them All: for, range, break, and the goto You Shouldn't Use
Developers coming from languages with separate `while` and `do-while` constructs often overcomplicate Go loops. The single-keyword design forces a consistent mental model, and labeled breaks eliminate a whole class of loop-control flags that make nested iteration harder to read.
Go has no `while` or `do-while` — every loop is a `for` loop with optional init, condition, and post statements. Dropping the init and post gives a while-style loop; dropping the condition creates an infinite loop that must be broken manually. The `range` clause handles slices, arrays, maps, and strings, returning an index (or key) and a value on each iteration. When ranging over a string, the index steps by byte position while the value is a full Unicode code point, so multi-byte characters cause the index to jump.
Control flow inside loops uses `break` to exit the current loop immediately and `continue` to skip the rest of the current iteration. Labeled breaks let you jump out of a specific outer loop in nested structures, a feature that avoids flag variables. The `goto` keyword exists but is discouraged outside of narrow error-cleanup patterns; labeled `break` and `continue` cover most multi-level control needs with better readability.
Conditional logic in Go follows the standard `if`/`else if`/`else` chain, with `switch` as a cleaner alternative when matching a single expression against multiple fixed values. Go's `switch` does not fall through by default, so no `break` is needed between cases. Logical operators `&&`, `||`, and `!` combine boolean expressions in the usual short-circuiting manner.
Labeled breaks are an underused feature that can flatten deeply nested loop logic. Instead of setting a `done` flag and checking it at every level, a single `break Outer` exits the exact scope you want, making the intent explicit.
The fact that ranging over a string gives runes but byte-based indices is a common source of off-by-one confusion for newcomers. Printing the index alongside the character, as the tutorial does, is a quick way to internalize the difference between byte position and character count.
Go's decision to make `switch` non-fallthrough by default removes an entire category of bugs that C-style languages suffer from when a missing `break` causes unintended case execution.