Можно ли реализовать методы не на структуре в Go
Что проверяют
Знаете ли вы, что метод в Go привязан к типу, а не к структуре, и какие ограничения действуют на получателя. Следом часто спрашивают про разницу между получателем-значением и получателем-указателем и про наборы методов.
Как отвечать
Да, можно. Метод объявляется на любом именованном (defined) типе из того же пакета, что бы ни лежало под ним:
- на базе примитива:
type Celsius float64и методfunc (c Celsius) String() string. Так устроенtime.Duration: этоint64с методамиString(),Seconds()и другими; - на слайсе или мапе:
type IDs []intс методамиLen,Less,Swap, какsort.IntSliceв стандартной библиотеке; - на функциональном типе:
http.HandlerFuncэтоfunc(ResponseWriter, *Request)с методомServeHTTP, и обычная функция через приведение становитсяhttp.Handler.
Ограничения тоже стоит назвать. Базовый тип получателя должен быть объявлен в вашем пакете, поэтому метод на int или на тип из чужого пакета не добавить, только через свой тип-обёртку. Получателем не может быть интерфейс или указательный тип вроде type P *T. Алиас type A = B новый тип не создаёт, так что через него методы чужому типу не добавить. Новый тип не наследует методы исходного: у type MyDur time.Duration метода String() нет, в отличие от встраивания в структуру.
Про получатели: набор методов T включает методы с получателем-значением, у *T в него входят все. Поэтому если методы интерфейса объявлены на *T, значение T этот интерфейс не реализует.
Где спотыкаются
Говорят, что методы можно объявлять на интерфейсах. Интерфейс только перечисляет методы, реализуют их конкретные типы.
Утверждают, что для int или string методов быть не может. Нельзя лишь добавить их к самим встроенным типам, а на type Name string можно сколько угодно.
Путают определение типа и алиас: пишут type Local = pkg.Type, объявляют на нём метод и получают ошибку компиляции.