weak and unique Packages

Updated

September 8, 2026

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 handle

unique.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.