Generics, and when not to · 3 MIN READ

A type parameter is written in square brackets

Write a function that works for several types without interface{} and without a cast.

Type parameters go in square brackets before the ordinary ones: func Map[T, U any](in []T, f func(T) U) []U. T and U are types the caller supplies, and in almost every call the compiler infers them so you write Map(names, length) with no brackets at all.

any is the constraint that allows every type. It is a real alias for interface{}, but in this position it means something different: with interface{} as a parameter type you get a value you must assert your way out of, and with any as a constraint you get the caller's actual type, checked at compile time.

That is the whole gain. The old version of this function returned []interface{} and every caller unpacked it; the generic one returns []U, and a mistake is a compile error rather than a panic.

SEE THE IDEA

One algorithm keeps the caller’s element type

  1. 01

    Caller

    go
    []string

    Supplies an element type

  2. 02

    Generic function

    go
    func Keep[T any](in []T)

    T is checked at compile time

  3. 03

    Typed result

    go
    []T

    No per-element type assertion

A constraint describes permitted types; a type argument selects one of them.

In practice

Keep a type parameter connected to the values whose type relationship matters. The compiler often infers it from ordinary arguments, but explicit instantiation is available when inference has no evidence. Generic code may use only the operations guaranteed by its constraint.

Watch out

An any constraint does not permit arithmetic, ordering or arbitrary methods on T.

Official reference ↗

Work through the exercise

go
package main

// Keep should return a new slice holding the elements the predicate
// returns true for, for any element type — no interface{} anywhere,
// and the result keeps the caller's type.

func main() {
	even := Keep([]int{1, 2, 3, 4}, func(n int) bool { return n%2 == 0 })
	println(len(even))
}
Try it yourself

Trace each value and write down your reasoning. Copy the source into GopherForge or your local Go environment to compile and check it. This web page does not execute your code or send it to a compiler service.

Progress stays in this browser. No account needed.