Go generics
Skill pngdeity/apm-user-repository/packages/golang-language/.apm/skills/go-generics
Use when deciding whether to use Go generics, writing generic functions or types, choosing constraints, or picking between type aliases and type definitions. Also use when a user is writing a utility function that could work with multiple types, even if they don't mention generics explicitly. Does not cover interface design without generics.From its SKILL.md
npx -y skills add pngdeity/apm-user-repository --skill go-genericsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
4.3 KB, 943 tokens by cl100k_base, as published. Nobody here has run it
Go Generics and Type Parameters
When to Use Generics
Start with concrete types. Generalize only when a second type appears.
Prefer Generics When
- Multiple types share identical logic (sorting, filtering, map/reduce)
- You would otherwise rely on
anyand excessive type switching - You are building a reusable data structure (concurrent-safe set, ordered map)
Avoid Generics When
- Only one type is being instantiated in practice
- Interfaces already model the shared behavior cleanly
- The generic code is harder to read than the type-specific alternative
"Write code, don't design types." — Robert Griesemer and Ian Lance Taylor
Decision Flow
Do multiple types share identical logic?
├─ No → Use concrete types
├─ Yes → Do they share a useful interface?
│ ├─ Yes → Use an interface
│ └─ No → Use generics
Bad:
// Premature generics: only ever called with int
func Sum[T constraints.Integer | constraints.Float](vals []T) T {
var total T
for _, v := range vals {
total += v
}
return total
}
Good:
func SumInts(vals []int) int {
var total int
for _, v := range vals {
total += v
}
return total
}
Type Parameter Naming
| Name | Typical Use |
|---|---|
T | General type parameter |
K | Map key type |
V | Map value type |
E | Element/item type |
For complex constraints, a short descriptive name is acceptable:
func Marshal[Opts encoding.MarshalOptions](v any, opts Opts) ([]byte, error)
Type Aliases vs Type Definitions
Type aliases (type Old = new.Name) are rare — use only for package migration
or gradual API refactoring.
Constraint Composition
Combine constraints with ~ (underlying type) and | (union):
type Numeric interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~float32 | ~float64
}
func Sum[T Numeric](vals []T) T {
var total T
for _, v := range vals {
total += v
}
return total
}
Use the constraints package or cmp package (Go 1.21+) for standard constraints
like cmp.Ordered instead of writing your own.
Read references/CONSTRAINTS.md when writing custom type constraints, composing constraints with ~ and |, or debugging type inference issues.
Common Pitfalls
Don't Wrap Standard Library Types
// Bad: generic wrapper adds complexity without value
type Set[T comparable] struct {
m map[T]struct{}
}
// Better: use map[T]struct{} directly when the usage is simple
seen := map[string]struct{}{}
Generics justify their complexity when they eliminate duplication across multiple call sites. A single-use generic is just indirection.
Don't Use Generics for Interface Satisfaction
// Bad: T is only used to satisfy an interface — just use the interface
func Process[T io.Reader](r T) error { ... }
// Good: accept the interface directly
func Process(r io.Reader) error { ... }
Avoid Over-Constraining
// Bad: constraint is more restrictive than needed
func Contains[T interface{ ~int | ~string }](slice []T, target T) bool { ... }
// Good: comparable is sufficient
func Contains[T comparable](slice []T, target T) bool { ... }
Quick Reference
| Topic | Guidance |
|---|---|
| When to use generics | Only when multiple types share identical logic and interfaces don't suffice |
| Starting point | Write concrete code first; generalize later |
| Naming | Single uppercase letter (T, K, V, E) |
| Type aliases | Same type, alternate name; use only for migration |
| Constraint composition | Use ~ for underlying types, ` |
| Common pitfall | Don't genericize single-use code or when interfaces suffice |
What ships with it: 1 file
4.6 KB alongside SKILL.md
references/
- CONSTRAINTS.md4.6 KB
Gives 0 of the 12 instructions most design frontend skills give in 943 tokens
Counted across 1,169 of the 1,878 authors here whose files we hold, read 2026-08-07
- Use CSS variables for color consistencyin 72 of 1169, across 23 files
- Commit to one bold aesthetic direction before codingin 72 of 1169, across 27 files
- Match implementation complexity to the aesthetic visionin 70 of 1169, across 20 files
- Add atmospheric background effects and texturesin 57 of 1169, across 9 files
- Use unexpected spatial compositions and layoutsin 56 of 1169, across 8 files
- Implement real working codein 55 of 1169, across 7 files
- Vary themes and aesthetics across different designsin 48 of 1169, across 7 files
- Launch chromium in headless modein 47 of 1169, across 4 files
- Close the browser when donein 47 of 1169, across 4 files
- Run provided scripts with help flag firstin 47 of 1169, across 4 files
- Wait for network idle statein 47 of 1169, across 4 files
- Use descriptive selectors for elementsin 47 of 1169, across 4 files
Said here and by no other author read
- combine constraints using tilde and pipe
- use the least restrictive constraint possible
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.