Go "method must have no type parameters": causes and fixes
Originally published on ImportStatic.
Since Go 1.27, a method on a concrete type may declare its own type parameters. On a current setup, "method must have no type parameters" therefore means one of two things: an older toolchain or an older go line in go.mod is still in charge, or the method is in an interface, where type parameters remain forbidden.
The exact wording of the message tells you which. We compiled this file, a small slice type with a generic Map method, under Go 1.25.13, 1.26.10 and 1.27.3 and collected every message:
type List[T any] []T // Map has its own type parameter R: a generic method. func (l List[T]) Map[R any](f func(T) R) List[R] { out := make(List[R], 0, len(l)) for _, v := range l { out = append(out, f(v)) } return out } func main() { nums := List[int]{1, 2, 3} fmt.Printf("%q\n", nums.Map(strconv.Itoa)) } With Go 1.27.3 and go 1.27 in go.mod, go vet is silent and go run . prints ["1" "2" "3"]. Every other combination fails with one of these messages.
What each message means
| You see | What compiled the file | Fix |
|---|---|---|
syntax error: method must have no type parameters | A Go 1.26 or older compiler | Build with Go 1.27 or newer |
generic method requires go1.27 or later (-lang was set to go1.26; check go.mod) | Go 1.27, but go.mod says go 1.26 | go get go@1.27.3 |
go: go.mod requires go >= 1.27 (running go 1.26.10; GOTOOLCHAIN=go1.26.10) | An older go command that isn't allowed to switch | Install Go 1.27, or drop the pinned GOTOOLCHAIN |
package requires newer Go version go1.27 (application built with go1.25) plus undefined: R | An editor or linter built with an older Go | Reinstall the tool with Go 1.27 |
interface method must have no type parameters | Any version, Go 1.27 included | Move the type parameter to the interface |
The compiler is older than Go 1.27
Before 1.27 a method couldn't have type parameters at all, so Go 1.26.10 rejects the file at parse time:
# example.com/generic126 ./main.go:11:21: syntax error: method must have no type parameters go vet from the same toolchain reports it without the "syntax error" prefix, as vet: ./main.go:11:21: method must have no type parameters.
An older compiler usually gets there through the go line. Our module had go 1.26, and the machine's default go is 1.25.13. Under the default GOTOOLCHAIN=auto, the toolchain rules say that when the go line is newer than the bundled toolchain, the go command runs that version instead, downloading it if needed. So go build fetched a Go 1.26 toolchain on its own and printed the syntax error above, even though no one had installed Go 1.26 on purpose.
Go 1.27 is installed, but go.mod says 1.26
Under Go 1.27.3 the same module gets a different message:
# example.com/generic126 ./main.go:11:22: generic method requires go1.27 or later (-lang was set to go1.26; check go.mod) Generic methods are gated on the language version as well as the toolchain. Raise the go line; go get does that and switches toolchains for you:
$ go get go@1.27.3 go: updating go.mod requires go >= 1.27.3; switching to go1.27.3 go: upgraded go 1.26 => 1.27.3 After that, go run . printed ["1" "2" "3"].
In a library this has a cost. The toolchain docs define the go line as the minimum Go version for using the module, so one generic method in a public package moves every importer to 1.27. If you can't ask that of your users yet, use one of the rewrites further down.
The reverse case is a newer go line meeting an older go command that isn't allowed to switch. With GOTOOLCHAIN=local on Go 1.25.13:
go: go.mod requires go >= 1.27 (running go 1.25.13; GOTOOLCHAIN=local) GOTOOLCHAIN=local is usually set in CI images and Docker builds. Move those to a Go 1.27 image rather than lowering the go line.
Errors from editors and linters
If go build succeeds and your editor still underlines the method, look at the tool behind the editor. A program that analyses Go code with the standard go/parser and go/types packages uses the versions of those packages it was compiled with. The Go on your PATH plays no part.
We wrote a short checker that parses and type-checks one file with those two packages, and built it with each toolchain. Built with Go 1.25.13 and told the file is Go 1.27, it printed:
go/parser: main.go:11:21: method must have no type parameters go/types: main.go:1:1: package requires newer Go version go1.27 (application built with go1.25) go/types: main.go:11:39: undefined: R go/types: main.go:11:47: undefined: R go/types: main.go:12:19: undefined: R The undefined: R lines follow from the parser error. The Go 1.25 parser parses method type parameters only "for a better error message and improved error recovery", reports them, and then throws them away, so the type checker sees R used with no declaration. If your editor shows a pile of "undefined" errors on type parameter names, look for the "application built with" line. It names the Go the tool was compiled with, and go/types adds it exactly when the code asks for a newer version than that.
Built with Go 1.26.10, the checker's output was identical apart from "go1.26". Built with Go 1.27.3, it reported nothing, so reinstalling the tool with a Go 1.27 toolchain (for gopls, go install golang.org/x/tools/gopls@latest) clears the errors.
The go/types source also has the wording "methods cannot have type parameters", in signature.go, but it only fires when a syntax tree arrives with method type parameters still attached. Since go/parser drops them first, none of our runs printed it.
Interface methods still can't have type parameters
The Go 1.27 release notes say interface methods may not declare type parameters, and Go 1.27.3 rejects this:
type Mapper interface { Map[R any](f func(int) R) []R } ./main.go:4:5: interface method must have no type parameters ./main.go:4:25: undefined: R Changing the go line or the toolchain won't help here. The Go blog post on generic methods gives the reason: a value in an interface can be of any dynamic type, so the compiler would need code for the method with every possible type argument. A generic method on a concrete type can't satisfy an ordinary interface either; our Go generic methods article shows the "wrong type for method" error you get.
Two rewrites that compile on Go 1.26
When you can't move to 1.27, or the method has to sit behind an interface, two shapes have worked since Go 1.18: a package-level generic function, or the type parameter on the interface itself.
type List[T any] []T // Fix 1: a package-level generic function instead of a generic method. func Map[T, R any](l List[T], f func(T) R) List[R] { out := make(List[R], 0, len(l)) for _, v := range l { out = append(out, f(v)) } return out } // Fix 2: the type parameter moves from the method to the interface. type Mapper[R any] interface { Map(f func(int) R) []R } type Ints []int func (s Ints) Map(f func(int) string) []string { out := make([]string, 0, len(s)) for _, v := range s { out = append(out, f(v)) } return out } func main() { fmt.Printf("%q\n", Map(List[int]{1, 2, 3}, strconv.Itoa)) var m Mapper[string] = Ints{4, 5} fmt.Printf("%q\n", m.Map(strconv.Itoa)) } With go 1.26 in go.mod, go vet passed on Go 1.26.10 and the program printed ["1" "2" "3"] and ["4" "5"] on both 1.26.10 and 1.27.3.
The function form reads inside-out, Map(list, f) instead of list.Map(f). The interface form fixes R per interface instantiation, so Ints satisfies Mapper[string] and nothing else. A single value that can map to any result type chosen at the call site needs Go 1.27's generic methods, which exist only on concrete types.
If you're on 1.27 already, the upgrade notes we collected list what else moves when you raise the go line.
Originally published on ImportStatic. This article was drafted with AI assistance; every claim was checked against the sources linked in it and the code samples were compiled and run.
原文:https://www.a8q9.cn/en/article/go-method-must-have-no-type-parameters-causes-and-fixes-8d2dc8.html