Generics, and when not to · 3 MIN READ

A method can take its own type parameter

Write the method that could only be a function before Go 1.27.

Go 1.27 lets a method declare type parameters of its own, in addition to the ones its receiver already carries:

text
type List[E any] []E

func (l List[E]) Apply[F any](f func(E) F) List[F] {
	...
}

E comes from the receiver; F belongs to the method. Before this, the second one had no place to live, so this transformation was commonly written as a package-level function taking the collection as its first argument. That was not a style choice — the language had no way to write it as a method.

Like a generic function, a generic method is instantiated before it is called, and in ordinary code the compiler infers the type argument from what you pass. The judgement from the previous lessons still applies: this removes a restriction, it does not create an obligation. A method earns a type parameter when the transformation genuinely produces a different element type, and not because it now can have one.

SEE THE IDEA

A method can transform to a new element type

  1. 01

    Receiver type

    go
    Bag[E]

    E is fixed by the receiver

  2. 02

    Method parameter

    go
    Map[F any]

    F belongs to this method

  3. 03

    Result type

    go
    Bag[F]

    The mapping can change the element type

Go 1.27 adds method-specific type parameters.

In practice

Keep the receiver’s parameter and the method’s parameter separate in your reasoning. A mapping function consumes E and produces F; a result container stores F. The caller can often infer F from the callback. This lesson uses the Go 1.27 toolchain bundled with GopherForge.

Watch out

Interface methods cannot declare type parameters, and a generic method cannot implement an interface method.

Official reference ↗

Work through the exercise

go
package main

// Bag holds elements of one type. Give it a Map method that returns
// a Bag of whatever type the function produces — a method, not a
// package-level function.

type Bag[E any] struct {
	items []E
}

func main() {
	b := Bag[int]{items: []int{1, 2, 3}}
	println(len(b.Map(func(n int) string { return "x" }).items))
}
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.