Writing Generic Functions
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
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}))
}
Login to try C/C++/Java/PHP code in the editor
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
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)
}
Login to try C/C++/Java/PHP code in the editor
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
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)
}
Login to try C/C++/Java/PHP code in the editor
- Writing three near-identical functions (SumInts, SumFloats, ...) instead of a single generic Sum function.
- Using an overly permissive constraint (any) on a function that actually needs arithmetic operators, causing a compile error when + is used.
- Forgetting generic functions can still return multiple values and use all normal Go control flow -- generics only affect the type parameter mechanism.
- 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: