Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Senior Go developer skill covering concurrency patterns, gRPC microservices, generics, pprof optimization, and idiomatic testing.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/generics.md
1# Generics and Type Parameters23## Basic Type Parameters45```go6package main78// Generic function with type parameter9func Max[T constraints.Ordered](a, b T) T {10if a > b {11return a12}13return b14}1516// Multiple type parameters17func Map[T, U any](slice []T, fn func(T) U) []U {18result := make([]U, len(slice))19for i, v := range slice {20result[i] = fn(v)21}22return result23}2425// Usage26func main() {27maxInt := Max(10, 20) // T = int28maxFloat := Max(3.14, 2.71) // T = float6429maxString := Max("abc", "xyz") // T = string3031nums := []int{1, 2, 3}32doubled := Map(nums, func(n int) int { return n * 2 })33strings := Map(nums, func(n int) string { return fmt.Sprintf("%d", n) })34}35```3637## Type Constraints3839```go40import "constraints"4142// Built-in constraints43type Number interface {44constraints.Integer | constraints.Float45}4647func Sum[T Number](numbers []T) T {48var total T49for _, n := range numbers {50total += n51}52return total53}5455// Custom constraints with methods56type Stringer interface {57String() string58}5960func PrintAll[T Stringer](items []T) {61for _, item := range items {62fmt.Println(item.String())63}64}6566// Approximate constraint using ~67type Integer interface {68~int | ~int8 | ~int16 | ~int32 | ~int6469}7071type MyInt int7273func Double[T Integer](n T) T {74return n * 275}7677// Works with both int and MyInt78func main() {79fmt.Println(Double(5)) // int80fmt.Println(Double(MyInt(5))) // MyInt81}82```8384## Generic Data Structures8586```go87// Generic Stack88type Stack[T any] struct {89items []T90}9192func NewStack[T any]() *Stack[T] {93return &Stack[T]{94items: make([]T, 0),95}96}9798func (s *Stack[T]) Push(item T) {99s.items = append(s.items, item)100}101102func (s *Stack[T]) Pop() (T, bool) {103if len(s.items) == 0 {104var zero T105return zero, false106}107item := s.items[len(s.items)-1]108s.items = s.items[:len(s.items)-1]109return item, true110}111112func (s *Stack[T]) IsEmpty() bool {113return len(s.items) == 0114}115116// Usage117intStack := NewStack[int]()118intStack.Push(1)119intStack.Push(2)120121stringStack := NewStack[string]()122stringStack.Push("hello")123stringStack.Push("world")124```125126## Generic Map Operations127128```go129// Filter with generics130func Filter[T any](slice []T, predicate func(T) bool) []T {131result := make([]T, 0, len(slice))132for _, v := range slice {133if predicate(v) {134result = append(result, v)135}136}137return result138}139140// Reduce/Fold141func Reduce[T, U any](slice []T, initial U, fn func(U, T) U) U {142acc := initial143for _, v := range slice {144acc = fn(acc, v)145}146return acc147}148149// Keys from map150func Keys[K comparable, V any](m map[K]V) []K {151keys := make([]K, 0, len(m))152for k := range m {153keys = append(keys, k)154}155return keys156}157158// Values from map159func Values[K comparable, V any](m map[K]V) []V {160values := make([]V, 0, len(m))161for _, v := range m {162values = append(values, v)163}164return values165}166167// Usage168numbers := []int{1, 2, 3, 4, 5, 6}169evens := Filter(numbers, func(n int) bool { return n%2 == 0 })170171sum := Reduce(numbers, 0, func(acc, n int) int { return acc + n })172173m := map[string]int{"a": 1, "b": 2}174keys := Keys(m) // []string{"a", "b"}175values := Values(m) // []int{1, 2}176```177178## Generic Pairs and Tuples179180```go181// Generic Pair182type Pair[T, U any] struct {183First T184Second U185}186187func NewPair[T, U any](first T, second U) Pair[T, U] {188return Pair[T, U]{First: first, Second: second}189}190191func (p Pair[T, U]) Swap() Pair[U, T] {192return Pair[U, T]{First: p.Second, Second: p.First}193}194195// Usage196pair := NewPair("name", 42)197swapped := pair.Swap() // Pair[int, string]198199// Generic Result type (like Rust's Result<T, E>)200type Result[T any] struct {201value T202err error203}204205func Ok[T any](value T) Result[T] {206return Result[T]{value: value}207}208209func Err[T any](err error) Result[T] {210return Result[T]{err: err}211}212213func (r Result[T]) IsOk() bool {214return r.err == nil215}216217func (r Result[T]) Unwrap() (T, error) {218return r.value, r.err219}220221func (r Result[T]) UnwrapOr(defaultValue T) T {222if r.err != nil {223return defaultValue224}225return r.value226}227```228229## Comparable Constraint230231```go232// Find using comparable233func Find[T comparable](slice []T, target T) (int, bool) {234for i, v := range slice {235if v == target {236return i, true237}238}239return -1, false240}241242// Contains243func Contains[T comparable](slice []T, target T) bool {244_, found := Find(slice, target)245return found246}247248// Unique elements249func Unique[T comparable](slice []T) []T {250seen := make(map[T]struct{})251result := make([]T, 0, len(slice))252253for _, v := range slice {254if _, exists := seen[v]; !exists {255seen[v] = struct{}{}256result = append(result, v)257}258}259260return result261}262263// Usage264nums := []int{1, 2, 2, 3, 3, 4}265unique := Unique(nums) // []int{1, 2, 3, 4}266267idx, found := Find([]string{"a", "b", "c"}, "b") // 1, true268```269270## Generic Interfaces271272```go273// Generic interface274type Container[T any] interface {275Add(item T)276Remove() (T, bool)277Size() int278}279280// Implementation281type Queue[T any] struct {282items []T283}284285func (q *Queue[T]) Add(item T) {286q.items = append(q.items, item)287}288289func (q *Queue[T]) Remove() (T, bool) {290if len(q.items) == 0 {291var zero T292return zero, false293}294item := q.items[0]295q.items = q.items[1:]296return item, true297}298299func (q *Queue[T]) Size() int {300return len(q.items)301}302303// Function accepting generic interface304func ProcessContainer[T any](c Container[T], item T) {305c.Add(item)306fmt.Printf("Container size: %d\n", c.Size())307}308```309310## Type Inference311312```go313// Type inference works in most cases314func Identity[T any](x T) T {315return x316}317318// No need to specify type319result := Identity(42) // T inferred as int320str := Identity("hello") // T inferred as string321322// Type inference with constraints323func Min[T constraints.Ordered](a, b T) T {324if a < b {325return a326}327return b328}329330// Inferred from arguments331minVal := Min(10, 20) // T = int332minFloat := Min(1.5, 2.5) // T = float64333334// Explicit type when needed335result := Map[int, string]([]int{1, 2}, func(n int) string {336return fmt.Sprintf("%d", n)337})338```339340## Generic Channels341342```go343// Generic channel operations344func Merge[T any](channels ...<-chan T) <-chan T {345out := make(chan T)346var wg sync.WaitGroup347348for _, ch := range channels {349wg.Add(1)350go func(c <-chan T) {351defer wg.Done()352for v := range c {353out <- v354}355}(ch)356}357358go func() {359wg.Wait()360close(out)361}()362363return out364}365366// Generic pipeline stage367func Stage[T, U any](in <-chan T, fn func(T) U) <-chan U {368out := make(chan U)369go func() {370defer close(out)371for v := range in {372out <- fn(v)373}374}()375return out376}377378// Usage379ch1 := make(chan int)380ch2 := make(chan int)381382merged := Merge(ch1, ch2)383384numbers := make(chan int)385doubled := Stage(numbers, func(n int) int { return n * 2 })386strings := Stage(doubled, func(n int) string { return fmt.Sprintf("%d", n) })387```388389## Union Constraints390391```go392// Union of types393type StringOrInt interface {394string | int395}396397func Process[T StringOrInt](val T) string {398return fmt.Sprintf("%v", val)399}400401// More complex unions402type Numeric interface {403int | int8 | int16 | int32 | int64 |404uint | uint8 | uint16 | uint32 | uint64 |405float32 | float64406}407408func Abs[T Numeric](n T) T {409if n < 0 {410return -n411}412return n413}414415// Union with methods416type Serializable interface {417string | []byte418}419420func Serialize[T Serializable](data T) []byte {421switch v := any(data).(type) {422case string:423return []byte(v)424case []byte:425return v426default:427panic("unreachable")428}429}430```431432## Quick Reference433434| Feature | Syntax | Use Case |435|---------|--------|----------|436| Basic generic | `func F[T any]()` | Any type |437| Constraint | `func F[T Constraint]()` | Restricted types |438| Multiple params | `func F[T, U any]()` | Multiple type variables |439| Comparable | `func F[T comparable]()` | Types supporting == and != |440| Ordered | `func F[T constraints.Ordered]()` | Types supporting <, >, <=, >= |441| Union | `T interface{int \| string}` | Either type |442| Approximate | `~int` | Include type aliases |443