В Go предложили наконец добавить generic-методы — то есть методы, у которых могут быть собственные типовые параметры, как у обычных функций. Раньше такое не разрешали, и вот почему.
Методы в Go исторически воспринимали в первую очередь как способ реализовать интерфейсы. Если бы мы разрешили типовые параметры у конкретного метода, то пришлось бы разрешить их и у методов интерфейса. А с этим проблема: Go не знает на этапе компиляции, какой конкретный тип будет реализовывать интерфейс, и нельзя эффективно скомпилировать вызов такого generic-метода через интерфейс. Об этом говорили ещё в оригинальном proposal по дженерикам. В FAQ даже написали, что Go, скорее всего, никогда не добавит generic-методы.
Но авторы предлагают сменить точку зрения. Метод — это не только способ выполнить интерфейс. Это ещё и функция, привязанная к типу, и способ удобно писать цепочки вызовов (x.a().b().c() вместо c(b(a(x)))). Generic-методы полезны сами по себе. Если интерфейс синтаксически не может содержать метод с типовыми параметрами, то generic-метод просто не участвует в удовлетворении интерфейса — и это нормально.
Предлагается изменить синтаксис: объявление метода должно выглядеть как объявление функции, но с receiver. То есть func (r *T) MethodName[P any](x P). Вызов — как обычно: s.Method[int](42) или с выводом типа s.Method(x). Работают и method expressions, и method values: Reader.Read вернёт generic-функцию с сигнатурой [E any](*Reader, []E) (int, error).
Интерфейсы не меняются. Тип H с методом m[P any](P) не реализует интерфейс I с сигнатурой m(string), потому что сигнатуры не совпадают. Reader с Read[E any]([]E) не реализует io.Reader.
Generic-методы не будут доступны через reflect — по той же причине, что и uninstantiated generic-функции: в reflect нет механизма инстанцировать generic-значение.
Изменения в спецификации минимальны и обратно совместимы. Парсер уже допускает типовые параметры у методов, просто выдаёт ошибку — её надо убрать. Основная работа — в бэкенде компилятора и особенно в формате экспорта/импорта данных: это самый disruptive момент, так как нужно синхронизировать много экспортёров и импортёров в разных тулзах. go/types скорее всего не требует изменений в API — Signature уже умеет хранить параметры ресивера и метода. Инструментам понадобится один-два релизных цикла, чтобы адаптироваться.