Создание методов в Golang

После изучения данного урока вы сможете:

  • Объявлять новые типы в Go;
  • Переписывать функции в методы.

Методы являются функциями, что улучшают типы с помощью дополнительного поведения. Перед объявлением нового метода нужно объявить новый тип. В этом уроке мы используем функцию kelvinToCelsius из предыдущей статьи о функциях и трансформируем ее в тип через методы.

Форум Гоферов

Мы работаем над форумом для программистов на Golang. Очень нужны модераторы которые хотят помочь с ответами для новичков и помочь в развитии Go-сообщества.

Go на Форум

Уроки, статьи и Видео

Мы публикуем в паблике ВК и Telegram качественные обучающие материалы для быстрого изучения Go. Подпишитесь на нас в ВК и в Telegram. Поддержите сообщество Go программистов.

Go в ВК Go в Telegram

Содержание статьи

Поначалу может показаться, что методы являются теми же самыми функциями, просто с другим синтаксисом. Это верно. Методы предоставляют другой способ организации кода, что будет рассмотрен в дальнейшем на примерах. Для привнесения новых возможностей методы можно комбинировать с другими особенностями языка.

В Go есть встроенный функционал для уникального оперирования  числами и текстом (+), что было продемонстрировано в статье про конвертирование типов данных Go. Что, если вам нужно представить новый тип и привязать к нему определенный набор поведенческих черт? К примеру, float64 может не подойти для термометра, а для чего может понадобиться bark() тоже может быть не сразу понятно — с английского слово bark можно перевести как лай собаки или как кора дерева. У функций есть свое предназначение, типы и методы также предоставляют другой полезный способ организации кода для представления окружающего мира.

Перед началом урока можете поупражняться. Осмотритесь вокруг, какие вы видите типы, как они себя ведут.

Объявление новых типов Golang

В Go можно объявить множество типов. Иногда данные типы не вполне верно описывают значения, к которым они относятся.

Температура не является float64, хотя это может быть ее базовым типом. Температура измеряется в Цельсиях, Фаренгейтах или Кельвинах. Объявление новых типов не только делает код чище, но также помогает предотвратить ошибки.

Ключевое слово type объявляет новый тип с названием и базовым типом, что показано в следующем примере:

Числовой литерал 20, как и все числовые литералы, является нетипизированной константой. Ее можно присвоить переменной типа int, float64 или любому другому числовому типу. Тип celsius является новым числовым типом с таким же поведением, что и float64, так что присваивание в предыдущем листинге по-прежнему работает.

Вы также можете добавить значения температуре и в общем использовать ее как тип float64, как показано далее:

Тип celsius является уникальным типом, а не просто другим названием типа float64. Подробнее о возможности использования других названий типов в статье о работе со строкам в Go. Однако здесь при попытке использовать float64 выйдет ошибка:

При добавлении переменной warmUp ее нужно конвертировать в тип celsius. Такая версия действует:

Возможность создания собственных типов может быть очень полезной для улучшения читабельности и качества кода. В следующем коде показано, что типы celsius и fahrenheit не могут сравниваться или объединяться:

Вопрос для проверки:

В чем преимущества объявления новых типов, таких как celsius и fahrenheit?

Создание своих собственных типов данных в Golang

В предыдущем разделе были объявлены типы celsius и fahrenheit, что привнесло в код понятие температуры, но опустило подробности касательно области хранения. Типы float64 или float32 мало что говорят о значении переменных температуры, в то время как типы celsius, fahrenheit и kelvin передают нужный смысл.

После объявления типа его можно использовать везде, где вы будете использовать предварительно объявленные типы Go (int, float64, string и так далее), включая параметры и результаты функции, как показано в следующем примере:

Функция kelvinToCelsius примет только аргумент типа kelvin, что может предотвратить глупые ошибки. Она не примет аргумент неправильного типа вроде fahrenheit, kilometers и даже float64. Go в определенном плане является проблематичным языком, поэтому передать значение литерала или нетипизированную константу все еще возможно. Вместо написания kelvinToCelsius(kelvin(294)) вы можете написать kelvinToCelsius(294).

Возвращаемый от kelvinToCelsius результат принадлежит типу celsius, а не kelvin, поэтому перед возвращением типа нужно его конвертировать в celsius.

Задание для проверки:

Напишите функцию celsiusToKelvin, что использует типы celsius и kelvin, определенные в Листинге 4. Используйте ее для конвертации 127° C, температуры освещенной солнцем поверхности луны, в градусы Кельвина.

Добавление поведения типам через методы Go

На протяжении десятилетий классические объектно-ориентированные языки предполагали, что методы принадлежат классам. В Go по-другому. Здесь нет классов или даже объектов, но есть методы. Это может кажется странным, однако методы в Go на самом деле более гибкие, чем во многих языках программирования прошлого.

Функции вроде kelvinToCelsius, celsiusToFahrenheit, fahrenheitToCelsius и celsiusToKelvin отлично справляются с работой, но не идеально. Объявление нескольких методов поможет сделать код для конвертации температуры более кратким и понятным.

Методы можно связать с любым типом, объявленным в том же пакете, но не с заранее объявленными типами (int, float64 и так далее). Способ объявления типа нам уже известен:

Тип kelvin обладает тем же поведением, что и базовый тип float64. Вы можете складывать, умножать и осуществлять другие операции над значениями kelvin, как с вещественными числами. Объявление метода для конвертации kelvin в celsius такое же простое, как и объявление функции. Они оба начинаются с ключевого слова func и тело функции идентично телу метода:

Метод celsius не принимает никаких параметров, но перед его названием значится что-то вроде параметра. Это приемник, как показано на схеме ниже. Методы и функции могут принимать много параметров, однако у методов также должен быть приемник. Внутри тела метода celsius приемник действует как и любой другой параметр.

Объявление метода Go

Объявление метода

Синтаксис метода отличается от вызова функции:

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

Теперь, когда преобразование температуры является методом типа kelvin, название вроде kelvinToCelsius является излишним. В пакете может быть только одна функция с заданным названием, что должно отличаться от названия типа, поэтому функция celsius, которая возвращает тип celsius, невозможна. Однако каждый тип температуры может предоставить метод celsius. К примеру, тип fahrenheit может быть улучшен следующим образом:

Создается приятная симметрия, где у каждого типа температуры может быть метод celsius для конвертации в градусы Цельсия.

Задание для проверки:

Идентифицируйте приемника в данной декларации метода: func (f fahrenheit) celsius() celsius.

Заключение

  • Объявление собственных типов может сделать код более читабельным и понятным;
  • Методы подобны функциям, связанным с типом посредством указанного приемника
    перед названием метода. Методы могут принимать несколько параметров и возвращать
    несколько результатов, как и функции, но у них всегда должен быть один приемник. В теле метода приемник ведет себя так же, как и любой другой параметр;
  • В синтаксисе вызова метода используется точка с переменной подходящего типа, следующим за ней, названием метода и другими аргументами.

Итоговое задание для проверки: 

Напишите программу с типами celsius, fahrenheit и kelvin и методами для конвертации из одного типа температуры в другой.