Frontend Labs
⋯

12. Strings, runes, bytes, and Unicode

12.1 A Go string is UTF-8 bytes, not characters

s := "héllo"
fmt.Println(len(s))          // 6 — 'é' is 2 bytes in UTF-8, not 1
fmt.Println(len([]rune(s)))  // 5 — rune count matches human intuition

Indexing a string with s[i] gives you a byte, not a character. for i, r := range s gives you rune-by-rune iteration with i as the byte offset of each rune's start (which can skip values for multi-byte runes) — this trips up almost everyone once.

12.2 Strings are immutable; conversions to []byte copy

b := []byte(s) // allocates and copies
s2 := string(b) // allocates and copies back

Because of that copy cost, hot paths that build strings incrementally should use strings.Builder (amortized-growth, like append on a slice) instead of repeated + concatenation:

var sb strings.Builder
for _, part := range parts {
	sb.WriteString(part)
	sb.WriteByte('\n')
}
result := sb.String() // one final allocation, not N

12.3 The strings, strconv, and unicode/utf8 packages

strings.Split, strings.Join, strings.Contains, strings.TrimSpace, strconv.Itoa/Atoi, strconv.ParseFloat, and utf8.RuneCountInString cover the overwhelming majority of text-munging you'll do. Reach for regular expressions (regexp) only when a fixed-pattern parse genuinely isn't enough — they're slower and harder to read than they look.

12.4 Real-world example

A CLI that accepts --size=10MB needs to split the numeric prefix from the unit suffix, strconv.ParseFloat the number, and look up the unit in the iota-based Unit type from Chapter 3 — three standard-library calls, no regex needed, and it handles "1.5GB" just as easily as "10MB".


Generated from real-life-golang-guide.md · 8 Oct 2026 16:36