Control Flow
Go's control constructs — if/else with an init statement, the single for loop in all its forms, switch without fallthrough, range, and panic/recover.
6 questions
JuniorTheoryVery commonWhat loop forms does Go's single for keyword provide?
What loop forms does Go's single for keyword provide?
Go has one loop keyword, for, in three shapes: the C-style for init; cond; post {} with all three clauses, the while-style for cond {} with just the condition, and the infinite for {}. break exits and continue skips to the next iteration.
Common mistakes
- ✗Looking for a separate
whileordo-whilekeyword in Go - ✗Writing
for true {}instead of the bare infinitefor {} - ✗Assuming
break/continuecannot target an outer loop via a label
Follow-up questions
- →How does a labelled
breakdiffer from a labelledcontinue? - →What scope does a variable declared in the
forinit clause have?
JuniorTheoryCommonHow do if/else work in Go, including the init statement?
How do if/else work in Go, including the init statement?
Go's if takes a bare boolean condition: no parentheses, yet braces are always required. An optional init statement like if x := f(); cond {} runs first, and its name is scoped to the if/else only. else stays on the closing brace's line.
Common mistakes
- ✗Wrapping the condition in parentheses or dropping the braces, C-style
- ✗Reading an init-statement variable after the
if/elseblock ends - ✗Putting
elseon its own line below the closing brace
Follow-up questions
- →Why does Go reject
elseon a new line — what rule causes it? - →How does the
if-init scope interact with shadowing an outer name?
JuniorTheoryCommonWhat does for range iterate over and what does it yield?
What does for range iterate over and what does it yield?
for range walks built-in collections: over a slice or array it yields (index, value), over a map (key, value) in random order, over a string a byte index plus the rune, and over a channel each value until it closes. _ drops a value you skip.
Common mistakes
- ✗Expecting
(value, index)instead of Go's(index, value)order - ✗Assuming map ranging visits keys in a stable or sorted order
- ✗Thinking a string range yields bytes rather than rune code points
Follow-up questions
- →Why does a string range step by byte index but yield runes?
- →When does ranging a channel stop, and what closes that loop?
JuniorTheoryCommonHow does Go's switch differ from C's regarding fallthrough?
How does Go's switch differ from C's regarding fallthrough?
In Go a case does NOT fall through: control leaves the switch after the matched case, so no trailing break is needed. You opt into C's behaviour with an explicit fallthrough, and an expressionless switch {} replaces an if-else chain.
Common mistakes
- ✗Adding a trailing
breakto each case as one would in C - ✗Expecting cases to fall through unless
fallthroughis written - ✗Not knowing an expressionless
switch {}can replace an if-else chain
Follow-up questions
- →What does
fallthroughdo to the next case's own condition check? - →How does a type
switchdiffer from this value-matching switch?
JuniorTheoryOccasionalWhat do panic and recover do, and where does recover work?
What do panic and recover do, and where does recover work?
panic stops normal flow and unwinds the stack, running deferred calls on the way up; unhandled, it crashes. recover works only inside a deferred function: it returns the panic value and stops the unwinding. Use both only for exceptional cases.
Common mistakes
- ✗Calling
recoveroutside a deferred function, where it returns nil - ✗Using
panic/recoverfor ordinary errors instead of returningerror - ✗Assuming deferred calls are skipped while a panic unwinds the stack
Follow-up questions
- →What does
recoverreturn when no panic is currently in flight? - →How does a panic in one goroutine affect the others in the program?
MiddleTheoryOccasionalWhen does an expressionless switch replace an if-else chain?
When does an expressionless switch replace an if-else chain?
An expressionless switch {} carries no value, so each case is its own boolean test. Go runs the first true case top to bottom, then exits — cleaner than a long if/else if chain. An explicit fallthrough runs the next case unconditionally.
Common mistakes
- ✗Thinking every true case runs, not just the first matched one
- ✗Believing
fallthroughre-checks the next case's condition before running - ✗Adding a value after
switchwhen an expressionless form is intended
Follow-up questions
- →How does
fallthroughbehave if it sits in the final case of a switch? - →When is a long
if/else ifchain still clearer than this switch?