String Iteration
Fast recall
Quick revision
Core answer
Whether you understand String Iteration beyond memorized syntax.
Giving a definition without explaining a practical trade-off.
Connect the concept to a small production example and state its complexity or failure mode.
Interview-ready guide
Interview answer
The range form is the idiomatic iteration, and its two returns carry the subtlety:
s := "héllo"
for i, r := range s {
fmt.Println(i, r)
// 0 104 — 'h' at byte 0
// 1 233 — 'é' at byte 1 (2 bytes wide)
// 3 108 — 'l' at byte 3 — offset JUMPED past é
// 4 108, 5 111
}Executed. The index is a BYTE OFFSET — advancing by each rune's UTF-8 width. The value is the decoded code point — safe for character logic.
The byte-level alternative:
for i := 0; i < len(s); i++ {
b := s[i] // 104, 195, 169, 108, 108, 111
}No offset jumps — but values at multi-byte positions are encoding fragments, not characters.
The mistake being tested: combining the classic loop with character comparisons — s[i] == 'é' never fires (s[i] is byte 195, not rune 233). That class of bug is why range is the default.
String Iteration
Direct Answer
for i, r := range s — i is a BYTE OFFSET, r is the decoded RUNE (code point). The offset advances by each rune's width (1-4 bytes). For byte-level iteration: a classic loop with s[i], or range []byte(s).
Deep Dive & Architecture
The decoder behind range: each iteration reads the current byte, infers the width from its leading bits (UTF-8 is self-synchronizing forward), gathers the bytes, decodes, returns (offset, rune). O(n) total, O(1) per rune, no allocation — decoding in registers.
Why byte-offset (not rune-index) for the first return: s[start:end] slices by BYTES, and range's i is exactly where each rune starts — substring building from iteration output composes directly: for i, r := range s { if r == target { return s[i:] } }. A rune-index loop can't slice without recomputing offsets.
The invalid-UTF-8 case: a Go string CAN hold arbitrary bytes. range handles invalid sequences by yielding U+FFFD (replacement character) with width 1 — no panic, no stop. That makes range safe over ANY string — and explains why byte and rune loops can disagree on corrupt input's count.
The two real-world jobs the two modes map to: structure scanning (delimiters, patterns) wants byte offsets (found positions slice cleanly); character logic (rendering, case, width) wants runes. range gives both — which is why it's the loop.
Common Mistakes & Pitfalls
Giving a definition without explaining a practical trade-off.
Check your understanding
Answer these without looking back at the article.
- When would you use String Iteration in a real project?
- How would you compare String Iteration with an alternative?
- What is a common mistake when using String Iteration?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.