Разница между функциями и методами в Go. Почему методы не могут иметь type parameters
Допустим есть такой код:
package main
import "fmt"
type Slice struct {
values []string
}
func (sl Slice) String() string {
s := "Slice{"
for _, val := range sl.values {
s += val + ", "
}
return s + "}"
}
func Append[elementType fmt.Stringer](sl *Slice, arr []elementType) {
for _, el := range arr {
sl.values = append(sl.values, el.String())
}
}
type StringStringer string
func (s StringStringer) String() string {
return string(s)
}
func main() {
arr := []StringStringer{StringStringer("abba"), StringStringer("caba")}
sl := Slice{make([]string, 0)}
Append(&sl, arr)
fmt.Println(sl)
}
Он работает.
А теперь если сделать функцию Append методом:
func (sl *Slice)Append[elementType fmt.Stringer](arr []elementType) {
Появляется ошибка syntax error: method must have no type parameters. Что означает эта ошибка мне конечно понятно.
Появляется вопрос, что такое методы в go? До этого я рассматривал их как синтаксический сахар, то есть реальной разницы между func (a *A) f() {} и func f(a *A) {} я не видел. Но получается это не так.
Почему методы не могут иметь type parameters?
И можно ли как-то оставить метод в моем коде, или из-за дженериков совсем не получиться?
Ответы (1 шт):
Если коротко, то основное назначение методов - поддержка интерфейсов. Например, тип StringStringer реализует метод String, тем самым он реализует интерфейс fmt.Stringer. Но что делать с методом Append[T fmt.Stringer]? Дженерики не допускаются в интерфейсах. Ключевая парадигма Go - делать все проверки на этапе компиляции. В случае дженериков в интерфейсах это может привести к избыточной генерации кода, от чего авторы языка пока отказались, запретив дженерики в интерфейсах.
Поэтому запретили дженерики и в методах. Если нужна некая обобщённая операция, используйте функции, а не методы.