Generic methods

July 28, 2023

Type definitions

A generic type may also have methods associated with it. In this case, the method receivers must declare the same number of type parameters as present in the generic type definition.

// The method Len returns the number of elements in the linked list l.
func (l *List[T]) Len() int  { … }

This probably needs further explanation. Or an example. It did for me.

Let’s look at a simple generic type:

type Thing[T any] struct {
	value T
}

Now you might think you could define a method on this type as so:

func (t *Thing) Foo() { ... } // compilation fails: cannot use generic type Thing[T any] without instantiation

But what we’ve just read says this doesn’t work. You must inclue the correct number of type parameters (in this case one) in the method definition:

func (t *Thing[T]) Type() string { // valid
	return fmt.Sprintf("%T", t.value)
}

But why? Perhaps to distinguish between a non-generic type of the same name? Nope, that’s invalid…

type Thing[T any] struct {
	value T
}

type Thing struct { // compilation fails: Thing redeclared in this block
	value any
}

Well, you can actually use the type parameter within the method. Here’s a re-implementation of my earlier Type() method:

func (t *Thing[T]) Type2() string {
	var x T
	return fmt.Sprintf("%T", x)
}

See this example on the playground

Quotes from The Go Programming Language Specification Version of December 15, 2022


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content


Go 1.24.0 is here!

Go 1.24 is released! Yay! That means a short re-visit to the Go spec, as we look at things that have changed. From the release notes we see that there’s really only one significant change: Changes to the language¶ Go 1.24 now fully supports generic type aliases: a type alias may be parameterized like a defined type. See the language spec for details. For now, the feature can be disabled by setting GOEXPERIMENT=noaliastypeparams; but the aliastypeparams setting will be removed for Go 1.


Type switches with generics

More live coding today! Join me! And bring your questions. Type switches … A type parameter or a generic type may be used as a type in a case. If upon instantiation that type turns out to duplicate another entry in the switch, the first matching case is chosen. func f[P any](x any) int { switch x.(type) { case P: return 0 case string: return 1 case []P: return 2 case []byte: return 3 default: return 4 } } var v1 = f[string]("foo") // v1 == 0 var v2 = f[byte]([]byte{}) // v2 == 2 The example included is nice, because it shows two examples of the type parameter P being used: Both the first case (case P) and third (case []P) use the type parameter.


Type switching on a non-interface value. Sorta.

Type switches … Cases then match actual types T against the dynamic type of the expression x. As with type assertions, x must be of interface type, but not a type parameter, and each non-interface type T listed in a case must implement the type of x. The types listed in the cases of a type switch must all be different. TypeSwitchStmt = "switch" [ SimpleStmt ";" ] TypeSwitchGuard "{" { TypeCaseClause } "}" .

Get daily content like this in your inbox!

Subscribe