Frontend Labs
⋯

52. What's really behind a slice, a map, and a string

52.1 Slice — covered fully in Chapter 6

A three-word header: pointer, length, capacity. Worth repeating here because it's the single most consequential piece of "what's really there" knowledge in the whole language.

52.2 Map — a hash table of buckets, with a twist

Go's map is implemented as an array of buckets, each holding a small fixed number of key/value pairs plus overflow bucket pointers for collisions, with the array growing (and old buckets migrating incrementally, not all at once) as the map fills. The "twist": Go deliberately randomizes the starting bucket for iteration precisely to prevent programs from ever depending on a stable order (Chapter 7.3) — this is enforced by the implementation, not just documented as unspecified.

52.3 String — a two-word, read-only view

type stringHeader struct {
	ptr *byte // pointer to an immutable byte array
	len int
}

No capacity field, because strings never grow in place — every operation that "modifies" a string (concatenation, slicing rules aside) allocates a new one. Slicing a string (s[2:5]) does share the underlying byte array without copying, exactly like slicing a slice (Chapter 6.2) — one more reason large substrings of a huge string you no longer need the rest of can pin that whole backing array in memory unless you explicitly copy the substring out.

52.4 Real-world example

A service parsing huge log lines and storing only a short substring (say, a request ID) per entry can accidentally retain the entire original line's byte array in memory for every stored substring, because slicing a string doesn't copy. The fix mirrors Chapter 6's slice-aliasing fix: strings.Clone(sub) (Go 1.18+) forces an actual copy, letting the original large string be garbage collected.


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