Frontend Labs
⋯

32. Reflection and unsafe: when, and why rarely

32.1 What reflection is actually for

Reflection (reflect package) is the right tool when you're writing a generic library that must operate on arbitrary, caller-defined types it cannot know at compile time: encoding/json, encoding/xml, dependency-injection containers, ORMs, struct validators. It is the wrong tool for application-level logic, where a type switch or generics almost always express intent more clearly and run faster.

32.2 unsafe: escaping Go's type system entirely

unsafe.Pointer lets you reinterpret memory across types, bypassing the type checker and the memory safety guarantees Go otherwise provides. It exists for a few legitimate uses — implementing extremely low-level data-structure tricks in the standard library itself, some cgo interop, and zero-copy conversions like unsafe.String/unsafe.Slice (Go 1.20+, replacing the older raw-pointer-arithmetic idiom) — and it is explicitly exempted from Go's backward-compatibility promise. If you find yourself reaching for unsafe in application code, that's a strong signal to look for a safe alternative first.

// A legitimate, narrow use: zero-copy []byte -> string when you can
// prove the []byte will never be mutated afterward.
func unsafeString(b []byte) string {
	return unsafe.String(unsafe.SliceData(b), len(b))
}

32.3 Real-world example

protobuf, gRPC, and high-throughput serialization libraries use unsafe internally to avoid copying bytes between a wire buffer and a Go string — but they hide it behind a safe public API. That's the correct shape: unsafe stays an implementation detail of a well-tested library, never a tool reached for casually in a service handler.


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