Yesterday we saw that when a method is defined on a generic type, the receiver must include type parameters. Now for all the relevant details:
Method declarations
…
… Syntactically, this type parameter declaration looks like an instantiation of the receiver base type: the type arguments must be identifiers denoting the type parameters being declared, one for each type parameter of the receiver base type. The type parameter names do not need to match their corresponding parameter names in the receiver base type definition, and all non-blank parameter names must be unique in the receiver parameter section and the method signature. The receiver type parameter constraints are implied by the receiver base type definition: corresponding type parameters have corresponding constraints.
type Pair[A, B any] struct { a A b B } func (p Pair[A, B]) Swap() Pair[B, A] { … } // receiver declares A, B func (p Pair[First, _]) First() First { … } // receiver declares First, corresponds to A in Pair
I don’t think there’s a lot I can add to this. I think the most important thing to remember here is that the type parameter names in a method definition do not need to match those in the type definition. This is consistent with the naming of function parameters in type defintions versus function definitions, or interface definitions versus method definitions.
// Type definition vs. method definition
type Foo[A, B any] struct {
a A
b B
}
func (f Foo[NotA, NotB]) Bar[NotA, NotB] { ... }
// Function type definition vs function definition
type FooFunc (a, b int)
var fooFunc = func(notA, notB int) { ... }
// Interface definition vs method definition
type barInterface interface {
Foo(a, b int)
}
var barImplementation struct {}
func (barImplementation) Foo(notA, notB int) { ... }
Quotes from The Go Programming Language Specification Version of August 2, 2023