История вопроса:
В Go часто возникают ситуации, когда встроенных типов недостаточно и нужно определить собственный тип данных с методами для инкапсуляции логики и расширения функционала. Это достигается созданием пользовательских типов (type) и методов (func (r Receiver) MethodName()).
Проблема:
Начинающие разработчики часто путаются — чем отличается объявление нового типа на основе существующего? Как правильно реализовать методы? Как решается вопрос копирования, передачи по значению/указателю? Ошибаются в области видимости, receiver типа и работе с embedded structs.
Решение:
Для определения собственного типа используется ключевое слово type. Методы реализуются с помощью receiver (приёмника) — это важно для работы с интерфейсами.
Пример кода:
type MyInt int func (m MyInt) Double() int { return int(m) * 2 } // Для структур: type User struct { Name string Age int } func (u *User) Birthday() { u.Age++ } var u = User{"Alice", 30} u.Birthday() // Age = 31
Ключевые особенности:
Наследуют ли пользовательские типы методы базового типа?
Нет. Если определить type MyInt int, то MyInt не имеет методов int. Не сработает, например, вызов String() или других методов базового типа.
Можно ли определять методы для алиаса типа?
Для alias (type MyType = ExistingType) добавить методы нельзя. Методы определяются только для новых типов (type MyType ExistingType), а не для псевдонимов.
Какой receiver использовать: указатель или значение?
Если метод должен изменять объект, лучше использовать указатель. Value receiver копирует структуру, это может привести к неожиданному поведению, если, например, структура содержит поля-срезы и карты.
Пример кода:
type Counter struct { value int } func (c *Counter) Inc() { c.value++ } func main() { c := Counter{} c.Inc() // только с указателем метод изменит value }
Программист создал type MySlice []int и ожидал, что методы []int, например, append, будут работать как методы на типе MySlice. В итоге выяснилось, что никаких методов нет, а обращаться к MySlice как к []int напрямую нельзя.
Плюсы:
Минусы:
Был определён type Counter int с методом Inc, что позволило использовать его в нескольких частях программы с общей логикой и без повторного кода.
Плюсы:
Минусы: