Go

How do you convert between []byte and string without copying, and what are the risks?

Question 70HardGo 1.22 to 1.25

Go 1.20 added the supported primitives unsafe.String, unsafe.StringData and unsafe.SliceData. They replace the old reflect.StringHeader/SliceHeader hacks, which are now deprecated and broke under GC changes.

import "unsafe"

// []byte -> string, zero copy
func bytesToString(b []byte) string {
	if len(b) == 0 {
		return ""
	}
	return unsafe.String(unsafe.SliceData(b), len(b))
}

// string -> []byte, zero copy (result MUST be treated as read-only)
func stringToBytes(s string) []byte {
	if s == "" {
		return nil
	}
	return unsafe.Slice(unsafe.StringData(s), len(s))
}

Risks:

  • Changing the bytes after converting to a string breaks immutability. Map keys holding that string get corrupted, and strings that callers cached change without warning.
  • Writing to bytes taken from a string can segfault, because string literals live in read-only memory. The runtime reports "unexpected fault address".
  • If the source is reused or pooled (sync.Pool), the string's contents change when the buffer is recycled.

When it is justified: hot paths found by profiling, such as parsers, serializers, or high-QPS proxies, where the source buffer is never changed afterwards. strings.Builder.String() uses this exact technique internally.

What the interviewer wants: you name the invariant ("the bytes must never be modified while the string is reachable"), you know the compiler already optimizes many conversions, and you measure before using unsafe.

More on Arrays, Slices, Maps & Strings

All 37 Arrays, Slices, Maps & Strings questions