Шаг 82.
Язык программирования Go.
Добавление методов

    На этом шаге рассмотрим добавление дополнительных методов в Go.

    Метод – это особого рода функция, которая вызывается относительно значения пользовательского типа, которое (обычно) передается вызываемому методу. Значение передается по указателю или по значению, в зависимости от того, как объявлен метод. Синтаксис определения методов практически идентичен синтаксису определения функций, за исключением того, что между ключевым словом func и именем метода в круглых скобках указывается приемник (receiver) либо как имя типа, которому принадлежит метод, либо как имя переменной с типом. При вызове метода переменной-приемнику (если указана) автоматически присваивается значение или указатель на значение, относительно которого был произведен вызов метода.

    В любой пользовательский тип можно добавить один или более методов. Приемником метода всегда будет значение типа или указатель на значение типа. Однако имена всех методов должны быть уникальными в пределах типа.

    Из требования к уникальности имени следует, что нельзя создать два метода с одинаковыми именами, один из которых принимает значение, а другой – указатель на значение.

    Еще одно следствие – отсутствие поддержки перегруженных методов , то есть методов с одинаковыми именами и разными сигнатурами. Один из способов реализовать подобие перегруженных методов заключается в создании методов с переменным числом аргументов, однако в языке Go принято использовать функции с уникальными именами. Например, тип strings.Reader предоставляет три разных метода чтения: strings.Reader.Read(), strings.Reader.ReadByte() и strings.Reader.ReadRune().

type Count int
func (count *Count) Increment() { *count++ }
func (count *Count) Decrement() { *count-- }
func (count Count) IsZero() bool { return count == 0 } 

    Это простой пользовательский тип, основанный на встроенном типе int, поддерживает три метода, из которых первые два принимают указатель на приемник, поскольку изменяют значение, относительно которого вызываются.

var count Count
i := int(count)
count.Increment()
j := int(count)
count.Decrement()
k := int(count)
fmt.Println(count, i, j, k, count.IsZero())

    Данный фрагмент демонстрирует практическое применение типа Count.

    Архив с примерами можно взять здесь.

    Рассмотрим чуть более сложный пользовательский тип, на этот раз основанный на структуре.

type Part struct {
    Id int // Именованное поле (агрегирование)
    Name string // Именованное поле (агрегирование)
}
func (part *Part) LowerCase() {
    part.Name = strings.ToLower(part.Name)
}
func (part *Part) UpperCase() {
    part.Name = strings.ToUpper(part.Name)
}
func (part Part) String() string {
    return fmt.Sprintf("%d %q", part.Id, part.Name)
}
func (part Part) HasPrefix(prefix string) bool {
    return strings.HasPrefix(part.Name, prefix)
}

    Методы, принимающие значение вместо указателя, не могут изменить значение, к которому применяются.

part := Part{5, "программирование"}
part.UpperCase()
part.Id += 11
fmt.Println(part, part.HasPrefix("п"))

    Когда пользовательские типы основаны на структурах, их значения можно создавать, указывая имя типа с фигурными скобками за ним, содержащими список начальных значений полей.

    После создания значения part его можно использовать для вызова методов (например, Part.UpperCase()), обращаться к его экспортируемым (общедоступным) полям (например, Part.Id) и выводить его содержимое, полагаясь на функции вывода в языке Go, всегда использующие метод String() типа, если он имеется.

    Архив с примерами можно взять здесь.

    На следующем шаге рассмотрим понятие множества методов типа в Go.


Предыдущий шаг Содержание Следующий шаг