What is the unique package (Go 1.23), and how does it help with memory for repeated strings?
Question 76HardGo 1.22 to 1.25
unique.Make[T comparable](v T) Handle[T] canonicalizes (interns) values. All calls with equal values return handles that point to the same single copy. Comparing two Handles is a pointer comparison, which is O(1) no matter how long the string is. h.Value() returns the stored value.
import "unique"
a := unique.Make("us-east-1")
b := unique.Make(strings.Clone("us-east-1")) // different backing bytes
fmt.Println(a == b, a.Value()) // true us-east-1
// Typical use: millions of log records with few distinct field values
type Record struct {
Region unique.Handle[string] // 1 pointer, shared storage
Msg string
}
How it works: the runtime keeps a global concurrent map from value to canonical copy. Entries are held weakly: when no Handle points to an entry, the GC can reclaim it. So unlike a hand-written map[string]string interning table, it does not grow forever. net/netip uses it to store IPv6 zone names.
Trade-offs:
Makecosts a hash and a lookup in a shared map, so it pays off only when values repeat a lot and are compared or kept for a long time.- Interned strings are copied (cloned) into the table, so a handle never pins a large parent buffer. That is another way to fix the substring leak.
- The weak-reference machinery behind it is exposed directly in Go 1.24 as the
weakpackage (weak.Make,weak.Pointer[T].Value), useful for caches that should not keep values alive.
More on Arrays, Slices, Maps & Strings
- Q74What does this print? (range over a nil pointer to an array, and range over an int)
- Q75How do range-over-func iterators work on slices and maps, and what happens if an iterator ignores yield's return value?