Go Tutorial · Functions and Methods · Lesson 21 of 30

Go Generics

Type parameters for functions and types, and constraints.

Type parameters

Since Go 1.18, functions and types can take type parameters in square brackets:

Example 1
package main

import (
	"fmt"
	"strings"
)

func Map[T, U any](items []T, f func(T) U) []U {
	out := make([]U, 0, len(items))
	for _, it := range items {
		out = append(out, f(it))
	}
	return out
}

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

type Stack[T any] struct{ items []T }

func (s *Stack[T]) Push(v T) { s.items = append(s.items, v) }

func (s *Stack[T]) Pop() (T, bool) {
	var zero T
	if len(s.items) == 0 {
		return zero, false
	}
	v := s.items[len(s.items)-1]
	s.items = s.items[:len(s.items)-1]
	return v, true
}

func main() {
	fmt.Println(Map([]int{1, 2, 3}, func(n int) string { return strings.Repeat("*", n) }))
	fmt.Println(Filter([]string{"go", "rust", "c"}, func(s string) bool { return len(s) > 1 }))

	s := Stack[string]{}
	s.Push("a")
	s.Push("b")
	top, _ := s.Pop()
	fmt.Println(top, len(s.items))
}

Output

[* ** ***]
[go rust]
b 1

Run this on your computer — see “Get Started” for setup.

Constraints

A constraint restricts the allowed types. any allows everything, comparable allows types usable with ==, and cmp.Ordered allows types that support <. You can define your own with a union of types:

Example 2
package main

import (
	"cmp"
	"fmt"
)

type Number interface {
	~int | ~int64 | ~float64
}

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

func Max[T cmp.Ordered](first T, rest ...T) T {
	m := first
	for _, v := range rest {
		if v > m {
			m = v
		}
	}
	return m
}

func Contains[T comparable](items []T, target T) bool {
	for _, it := range items {
		if it == target {
			return true
		}
	}
	return false
}

func main() {
	fmt.Println(Max(3, 9, 4), Max("pear", "apple"))
	fmt.Println(Sum([]int{1, 2, 3}), Sum([]float64{1.5, 2.25}))
	fmt.Println(Contains([]string{"a", "b"}, "b"))
}

Output

9 pear
6 3.75
true

Run this on your computer — see “Get Started” for setup.

Test yourself

Which constraint allows types that can be compared with ==?

  1. any
  2. comparable
  3. cmp.Ordered
  4. equal
Show answer

Answer: comparable