weak and unique Packages
weak and unique Packages
Overview
Go 1.24+ added first-class support for patterns that used to require finalizer hacks or string maps:
| Package | Role |
|---|---|
weak |
Weak pointers — do not keep the referent alive |
unique |
Canonicalize comparable values (interning) |
These show up in caches, symbol tables, and RPC codecs.
Diagram: Weak vs strong
diagram:
Strong[strong *T] -->|keeps alive| Obj[object]
Weak[weak.Pointer] -.->|does not keep| Obj
GC[GC] -->|collects| Obj
Weak2[weak.Value] -->|nil after| GC
U1[unique.Make a] --> H[canonical handle]
U2[unique.Make a] --> H
weak.Pointer
import "weak"
type heavy struct{ buf []byte }
func demo() {
h := &heavy{buf: make([]byte, 1<<20)}
wp := weak.Make(h)
h = nil
runtime.GC()
if v := wp.Value(); v != nil {
fmt.Println("still alive", len(v.buf))
} else {
fmt.Println("collected")
}
}Use cases:
- Caches that should not pin memory forever
- Canonical registries keyed by identity without leaks
Do not replace explicit cache eviction policies when you need deterministic memory bounds — combine weak refs with size limits.
unique.Handle
import "unique"
h1 := unique.Make("GET")
h2 := unique.Make("GET")
fmt.Println(h1 == h2) // true — same canonical handleunique.Make returns a handle for a comparable value; equal values collapse to one interned copy. Good for:
- Repeated strings (method names, header keys, enums-as-strings)
- Reducing duplicate allocations in large graphs
Handles compare with ==. Extract value with h.Value().
When Not To
- Tiny short-lived strings — interning overhead may lose
- Secrets — longer lifetime increases exposure window
- Non-comparable structures — not supported
Experiment
go mod init example
go run .package main
import (
"fmt"
"runtime"
"unique"
"weak"
)
func main() {
a := unique.Make("content-type")
b := unique.Make("content-type")
fmt.Println("unique equal", a == b, a.Value())
type node struct{ n int }
p := &node{n: 7}
w := weak.Make(p)
fmt.Println("before", w.Value() != nil)
p = nil
runtime.GC()
runtime.GC()
fmt.Println("after GC value?", w.Value() != nil)
}What to notice: Unique handles collapse equal values; weak pointers may become nil after GC once strong refs are gone (timing can vary — double GC is a demo heuristic).
Try next: Intern 100k duplicate strings with and without unique; compare runtime.MemStats.HeapAlloc.