Need the same operation for several types? Copying a function creates boilerplate, while accepting any may push type checks to run time. Generics let a function or type use type parameters that are fixed when it is instantiated. section 2.9.1
func getKeys(m any) ([]any, error) { #1
switch t := m.(type) {
default:
return nil, fmt.Errorf("unknown type: %T", t) #2
case map[string]int:
var keys []any
for k := range t {
keys = append(keys, k)
}
return keys, nil
case map[int]string:
// Copy the extraction logic
}
}
The type-switch version repeats key-extraction logic, rejects unsupported maps at run time, and returns []any, leaving callers to inspect or convert the keys. section 2.9.1
func getKeys[K comparable, V any](m map[K]V) []K { #1
var keys []K #2
for k := range m {
keys = append(keys, k)
}
return keys
}
One getKeys implementation accepts maps with different key and value types while returning []K. K must be comparable because a map cannot use every type as a key; V can be any. section 2.9.1
A type argument can be inferred from a call such as getKeys(m), or supplied explicitly as getKeys[string](m). Instantiation happens at compile time. Constraints can also narrow accepted types: a custom constraint may list ~int | ~string, and constraints can require methods. Type parameters work on types such as Node[T], but methods cannot declare their own type parameters. section 2.9.1
Choose the abstraction for a concrete need:
- Use type parameters to reuse data structures or functions across element types, such as linked lists and channel-merging functions. section 2.9.2
- Use them to factor out behavior when it avoids separate functions for each type, as with a slice and its comparison function. section 2.9.2
- Keep an interface when the code only calls its methods: a function that just calls Write gains nothing from a type parameter constrained to io.Writer. Reconsider generics when they make the code less clear. section 2.9.2
type SliceFn[T any] struct { #1
S []T
Compare func(T, T) bool #2
}
func (s SliceFn[T]) Len() int { return len(s.S) }
func (s SliceFn[T]) Less(i, j int) bool { return s.Compare(s.S[i], s.S[j]) }
func (s SliceFn[T]) Swap(i, j int) { s.S[i], s.S[j] = s.S[j], s.S[i] }
SliceFn[T] holds both a slice and a comparison function. Its methods satisfy sort.Interface, so the same wrapper can sort slices of different element types through sort.Sort. section 2.9.2



















