Разница между функциями и методами в Go. Почему методы не могут иметь type parameters

Рейтинг: 0Ответов: 1Опубликовано: 03.02.2023

Допустим есть такой код:

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?

И можно ли как-то оставить метод в моем коде, или из-за дженериков совсем не получиться?

Ответы

▲ 3Принят

Объяснение здесь

Если коротко, то основное назначение методов - поддержка интерфейсов. Например, тип StringStringer реализует метод String, тем самым он реализует интерфейс fmt.Stringer. Но что делать с методом Append[T fmt.Stringer]? Дженерики не допускаются в интерфейсах. Ключевая парадигма Go - делать все проверки на этапе компиляции. В случае дженериков в интерфейсах это может привести к избыточной генерации кода, от чего авторы языка пока отказались, запретив дженерики в интерфейсах.

Поэтому запретили дженерики и в методах. Если нужна некая обобщённая операция, используйте функции, а не методы.