{"id":"afae16bb-1c41-4701-8072-8207763e5739","shortId":"SqEkMy","kind":"skill","title":"go-generics","tagline":"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 generic","description":"# Go Generics and Type Parameters\n\n---\n\n## When to Use Generics\n\nStart with concrete types. Generalize only when a second type appears.\n\n### Prefer Generics When\n\n- Multiple types share identical logic (sorting, filtering, map/reduce)\n- You would otherwise rely on `any` and excessive type switching\n- You are building a reusable data structure (concurrent-safe set, ordered map)\n\n### Avoid Generics When\n\n- Only one type is being instantiated in practice\n- Interfaces already model the shared behavior cleanly\n- The generic code is harder to read than the type-specific alternative\n\n> \"Write code, don't design types.\" — Robert Griesemer and Ian Lance Taylor\n\n### Decision Flow\n\n```\nDo multiple types share identical logic?\n├─ No  → Use concrete types\n├─ Yes → Do they share a useful interface?\n│        ├─ Yes → Use an interface\n│        └─ No  → Use generics\n```\n\n**Bad:**\n\n```go\n// Premature generics: only ever called with int\nfunc Sum[T constraints.Integer | constraints.Float](vals []T) T {\n    var total T\n    for _, v := range vals {\n        total += v\n    }\n    return total\n}\n```\n\n**Good:**\n\n```go\nfunc SumInts(vals []int) int {\n    var total int\n    for _, v := range vals {\n        total += v\n    }\n    return total\n}\n```\n\n---\n\n## Type Parameter Naming\n\n| Name | Typical Use |\n|------|-------------|\n| `T` | General type parameter |\n| `K` | Map key type |\n| `V` | Map value type |\n| `E` | Element/item type |\n\nFor complex constraints, a short descriptive name is acceptable:\n\n```go\nfunc Marshal[Opts encoding.MarshalOptions](v any, opts Opts) ([]byte, error)\n```\n\n---\n\n## Type Aliases vs Type Definitions\n\nType aliases (`type Old = new.Name`) are rare — use only for package migration\nor gradual API refactoring.\n\n---\n\n## Constraint Composition\n\nCombine constraints with `~` (underlying type) and `|` (union):\n\n```go\ntype Numeric interface {\n    ~int | ~int8 | ~int16 | ~int32 | ~int64 |\n    ~float32 | ~float64\n}\n\nfunc Sum[T Numeric](vals []T) T {\n    var total T\n    for _, v := range vals {\n        total += v\n    }\n    return total\n}\n```\n\nUse the `constraints` package or `cmp` package (Go 1.21+) for standard constraints\nlike `cmp.Ordered` instead of writing your own.\n\n> Read [references/CONSTRAINTS.md](references/CONSTRAINTS.md) when writing custom type constraints, composing constraints with ~ and |, or debugging type inference issues.\n\n---\n\n## Common Pitfalls\n\n### Don't Wrap Standard Library Types\n\n```go\n// Bad: generic wrapper adds complexity without value\ntype Set[T comparable] struct {\n    m map[T]struct{}\n}\n\n// Better: use map[T]struct{} directly when the usage is simple\nseen := map[string]struct{}{}\n```\n\nGenerics justify their complexity when they eliminate duplication across\n**multiple call sites**. A single-use generic is just indirection.\n\n### Don't Use Generics for Interface Satisfaction\n\n```go\n// Bad: T is only used to satisfy an interface — just use the interface\nfunc Process[T io.Reader](r T) error { ... }\n\n// Good: accept the interface directly\nfunc Process(r io.Reader) error { ... }\n```\n\n### Avoid Over-Constraining\n\n```go\n// Bad: constraint is more restrictive than needed\nfunc Contains[T interface{ ~int | ~string }](slice []T, target T) bool { ... }\n\n// Good: comparable is sufficient\nfunc Contains[T comparable](slice []T, target T) bool { ... }\n```\n\n---\n\n## Quick Reference\n\n| Topic | Guidance |\n|-------|----------|\n| When to use generics | Only when multiple types share identical logic and interfaces don't suffice |\n| Starting point | Write concrete code first; generalize later |\n| Naming | Single uppercase letter (`T`, `K`, `V`, `E`) |\n| Type aliases | Same type, alternate name; use only for migration |\n| Constraint composition | Use `~` for underlying types, `|` for unions; prefer `cmp.Ordered` over custom |\n| Common pitfall | Don't genericize single-use code or when interfaces suffice |\n\n---\n\n## Related Skills\n\n- **Interfaces vs generics**: See [go-interfaces](../go-interfaces/SKILL.md) when deciding whether an interface already models the shared behavior without generics\n- **Type declarations**: See [go-declarations](../go-declarations/SKILL.md) when defining new types, type aliases, or choosing between type definitions and aliases\n- **Documenting generic APIs**: See [go-documentation](../go-documentation/SKILL.md) when writing doc comments and runnable examples for generic functions\n- **Naming type parameters**: See [go-naming](../go-naming/SKILL.md) when choosing names for type parameters or constraint interfaces","tags":["generics","golang","skills","cxuu","agent-skills","ai-agent","ai-assistant","claude","claude-code","codex","cursor","llm"],"capabilities":["skill","source-cxuu","skill-go-generics","topic-agent-skills","topic-ai-agent","topic-ai-assistant","topic-claude","topic-claude-code","topic-codex","topic-cursor","topic-golang","topic-llm"],"categories":["golang-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/cxuu/golang-skills/go-generics","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add cxuu/golang-skills","source_repo":"https://github.com/cxuu/golang-skills","install_from":"skills.sh"}},"qualityScore":"0.491","qualityRationale":"deterministic score 0.49 from registry signals: · indexed on github topic:agent-skills · 82 github stars · SKILL.md body (4,499 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-02T12:55:18.424Z","embedding":null,"createdAt":"2026-04-18T22:13:15.876Z","updatedAt":"2026-05-02T12:55:18.424Z","lastSeenAt":"2026-05-02T12:55:18.424Z","tsv":"'/go-declarations/skill.md':588 '/go-documentation/skill.md':609 '/go-interfaces/skill.md':569 '/go-naming/skill.md':627 '1.21':327 'accept':248,444 'across':403 'add':367 'alias':23,261,266,526,594,601 'alreadi':116,575 'also':27 'altern':134,529 'api':279,604 'appear':69 'avoid':104,453 'bad':173,364,423,458 'behavior':120,579 'better':380 'bool':475,488 'build':93 'byte':258 'call':179,405 'choos':17,596,629 'clean':121 'cmp':324 'cmp.ordered':332,544 'code':124,136,513,555 'combin':283 'comment':613 'common':355,547 'compar':374,477,483 'complex':241,368,398 'compos':346 'composit':282,536 'concret':61,157,512 'concurr':99 'concurrent-saf':98 'constrain':456 'constraint':18,242,281,284,321,330,345,347,459,535,635 'constraints.float':186 'constraints.integer':185 'contain':466,481 'could':38 'custom':343,546 'data':96 'debug':351 'decid':6,571 'decis':147 'declar':583,587 'defin':590 'definit':26,264,599 'descript':245 'design':139 'direct':385,447 'doc':612 'document':602,608 'duplic':402 'e':237,524 'element/item':238 'elimin':401 'encoding.marshaloptions':253 'error':259,442,452 'even':43 'ever':178 'exampl':616 'excess':88 'filter':79 'first':514 'float32':299 'float64':300 'flow':148 'func':182,203,250,301,436,448,465,480 'function':14,36,619 'general':63,226,515 'generic':3,11,13,49,51,58,71,105,123,172,176,365,395,411,418,496,551,564,581,603,618 'go':2,10,50,174,202,249,290,326,363,422,457,567,586,607,625 'go-declar':585 'go-document':606 'go-gener':1 'go-interfac':566 'go-nam':624 'good':201,443,476 'gradual':278 'griesem':142 'guidanc':492 'harder':126 'ian':144 'ident':76,153,502 'indirect':414 'infer':353 'instanti':112 'instead':333 'int':181,206,207,210,294,469 'int16':296 'int32':297 'int64':298 'int8':295 'interfac':115,165,169,293,420,431,435,446,468,505,558,562,568,574,636 'io.reader':439,451 'issu':354 'justifi':396 'k':229,522 'key':231 'lanc':145 'later':516 'letter':520 'librari':361 'like':331 'logic':77,154,503 'm':376 'map':103,230,234,377,382,392 'map/reduce':80 'marshal':251 'mention':48 'migrat':276,534 'model':117,576 'multipl':41,73,150,404,499 'name':221,222,246,517,530,620,626,630 'need':464 'new':591 'new.name':269 'numer':292,304 'old':268 'one':108 'opt':252,256,257 'order':102 'otherwis':83 'over-constrain':454 'packag':275,322,325 'paramet':54,220,228,622,633 'pick':20 'pitfal':356,548 'point':510 'practic':114 'prefer':70,543 'prematur':175 'process':437,449 'quick':489 'r':440,450 'rang':195,213,313 'rare':271 'read':128,338 'refactor':280 'refer':490 'references/constraints.md':339,340 'relat':560 'reli':84 'restrict':462 'return':199,217,317 'reusabl':95 'robert':141 'runnabl':615 'safe':100 'satisfact':421 'satisfi':429 'second':67 'see':565,584,605,623 'seen':391 'set':101,372 'share':75,119,152,162,501,578 'short':244 'simpl':390 'singl':409,518,553 'single-us':408,552 'site':406 'skill':561 'skill-go-generics' 'slice':471,484 'sort':78 'source-cxuu' 'specif':133 'standard':329,360 'start':59,509 'string':393,470 'struct':375,379,384,394 'structur':97 'suffic':508,559 'suffici':479 'sum':183,302 'sumint':204 'switch':90 'target':473,486 'taylor':146 'topic':491 'topic-agent-skills' 'topic-ai-agent' 'topic-ai-assistant' 'topic-claude' 'topic-claude-code' 'topic-codex' 'topic-cursor' 'topic-golang' 'topic-llm' 'total':191,197,200,209,215,218,309,315,318 'type':16,22,25,42,53,62,68,74,89,109,132,140,151,158,219,227,232,236,239,260,263,265,267,287,291,344,352,362,371,500,525,528,540,582,592,593,598,621,632 'type-specif':131 'typic':223 'under':286,539 'union':289,542 'uppercas':519 'usag':388 'use':4,9,28,57,156,164,167,171,224,272,319,381,410,417,427,433,495,531,537,554 'user':31 'util':35 'v':194,198,212,216,233,254,312,316,523 'val':187,196,205,214,305,314 'valu':235,370 'var':190,208,308 'vs':262,563 'whether':7,572 'without':369,580 'work':39 'would':82 'wrap':359 'wrapper':366 'write':12,33,135,335,342,511,611 'yes':159,166","prices":[{"id":"89ec2e0b-bf37-4d59-9d45-6a4fc188c319","listingId":"afae16bb-1c41-4701-8072-8207763e5739","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"cxuu","category":"golang-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T22:13:15.876Z"}],"sources":[{"listingId":"afae16bb-1c41-4701-8072-8207763e5739","source":"github","sourceId":"cxuu/golang-skills/go-generics","sourceUrl":"https://github.com/cxuu/golang-skills/tree/main/skills/go-generics","isPrimary":false,"firstSeenAt":"2026-04-18T22:13:15.876Z","lastSeenAt":"2026-05-02T12:55:18.424Z"}],"details":{"listingId":"afae16bb-1c41-4701-8072-8207763e5739","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"cxuu","slug":"go-generics","github":{"repo":"cxuu/golang-skills","stars":82,"topics":["agent-skills","ai-agent","ai-assistant","claude","claude-code","codex","cursor","go","golang","llm"],"license":"apache-2.0","html_url":"https://github.com/cxuu/golang-skills","pushed_at":"2026-03-15T19:32:10Z","description":"AI Agent Skills for idiomatic, production-ready Go code, distilled from Google, Uber, Community","skill_md_sha":"d3bbc90af4832f4c16ae1e97965895238816dbaa","skill_md_path":"skills/go-generics/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/cxuu/golang-skills/tree/main/skills/go-generics"},"layout":"multi","source":"github","category":"golang-skills","frontmatter":{"name":"go-generics","license":"Apache-2.0","description":"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 (see go-interfaces).","compatibility":"Requires Go 1.18+ (generics were introduced in Go 1.18)"},"skills_sh_url":"https://skills.sh/cxuu/golang-skills/go-generics"},"updatedAt":"2026-05-02T12:55:18.424Z"}}