← Back to Go Course | Chapter 12: Generics | Lesson 3 of 6

Writing Generic Functions

Writing a generic function is like designing a tool that adapts its grip to fit whatever size handle you hand it, instead of building a separate tool for every handle size.

A Generic Sum Function

A function that sums a slice of numbers can be written once with a type parameter constrained to numeric types, instead of writing SumInts and SumFloats separately.

Example: A Generic Sum Function

markup
package main

import "fmt"

type Number interface {
	int | float64
}

func Sum[T Number](nums []T) T {
	var total T
	for _, n := range nums {
		total += n
	}
	return total
}

func main() {
	fmt.Println(Sum([]int{1, 2, 3}))
	fmt.Println(Sum([]float64{1.5, 2.5}))
}

A Generic Filter Function

Generic functions work well with higher-order functions too, like a Filter that keeps only elements matching a predicate, regardless of what type the slice actually holds.

Example: A Generic Filter Function

markup
package main

import "fmt"

func Filter[T any](items []T, keep func(T) bool) []T {
	var result []T
	for _, item := range items {
		if keep(item) {
			result = append(result, item)
		}
	}
	return result
}

func main() {
	nums := []int{1, 2, 3, 4, 5, 6}
	even := Filter(nums, func(n int) bool { return n%2 == 0 })
	fmt.Println(even)
}

Multiple Type Parameters

A generic function can declare more than one type parameter, useful for functions like a map-transform that convert a slice of one type into a slice of a different type.

Example: Multiple Type Parameters

markup
package main

import "fmt"

func Map[T, U any](items []T, f func(T) U) []U {
	result := make([]U, len(items))
	for i, item := range items {
		result[i] = f(item)
	}
	return result
}

func main() {
	nums := []int{1, 2, 3}
	strs := Map(nums, func(n int) string {
		return fmt.Sprintf("#%d", n)
	})
	fmt.Println(strs)
}
Common Mistakes
  1. Writing three near-identical functions (SumInts, SumFloats, ...) instead of a single generic Sum function.
  2. Using an overly permissive constraint (any) on a function that actually needs arithmetic operators, causing a compile error when + is used.
  3. Forgetting generic functions can still return multiple values and use all normal Go control flow -- generics only affect the type parameter mechanism.
Chapter Summary
  • A generic function is declared with type parameters, then implemented once using those parameters like any other type.
  • Constraints determine which operators and methods are valid to use on a type parameter inside the function.
  • Generic functions eliminate near-duplicate code across multiple concrete-typed variants.
  • Slices, maps, and other composite types can all use type parameters as their element type.
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.