После изучения данного урока вы сможете:
- Объявлять новые типы в Go;
- Переписывать функции в методы.
Методы являются функциями, что улучшают типы с помощью дополнительного поведения. Перед объявлением нового метода нужно объявить новый тип. В этом уроке мы используем функцию kelvinToCelsius
из предыдущей статьи о функциях и трансформируем ее в тип через методы.
Рекомендуем вам супер TELEGRAM канал по Golang где собраны все материалы для качественного изучения языка. Удивите всех своими знаниями на собеседовании! 😎
Мы публикуем в паблике ВК и Telegram качественные обучающие материалы для быстрого изучения Go. Подпишитесь на нас в ВК и в Telegram. Поддержите сообщество Go программистов.
Содержание статьи
- Объявление новых типов Golang
- Создание своих собственных типов данных
- Добавление поведения типам через методы Go
Поначалу может показаться, что методы являются теми же самыми функциями, просто с другим синтаксисом. Это верно. Методы предоставляют другой способ организации кода, что будет рассмотрен в дальнейшем на примерах. Для привнесения новых возможностей методы можно комбинировать с другими особенностями языка.
В Go есть встроенный функционал для уникального оперирования числами и текстом (+), что было продемонстрировано в статье про конвертирование типов данных Go. Что, если вам нужно представить новый тип и привязать к нему определенный набор поведенческих черт? К примеру, float64 может не подойти для термометра, а для чего может понадобиться bark()
тоже может быть не сразу понятно — с английского слово bark можно перевести как лай собаки или как кора дерева. У функций есть свое предназначение, типы и методы также предоставляют другой полезный способ организации кода для представления окружающего мира.
Перед началом урока можете поупражняться. Осмотритесь вокруг, какие вы видите типы, как они себя ведут.
Объявление новых типов Golang
В Go можно объявить множество типов. Иногда данные типы не вполне верно описывают значения, к которым они относятся.
Температура не является float64
, хотя это может быть ее базовым типом. Температура измеряется в Цельсиях, Фаренгейтах или Кельвинах. Объявление новых типов не только делает код чище, но также помогает предотвратить ошибки.
Ключевое слово type
объявляет новый тип с названием и базовым типом, что показано в следующем примере:
1 2 3 4 5 |
type celsius float64 // Базовый тип float64 var temperature celsius = 20 fmt.Println(temperature) // Выводит: 20 |
Числовой литерал 20, как и все числовые литералы, является нетипизированной константой. Ее можно присвоить переменной типа int, float64
или любому другому числовому типу. Тип celsius
является новым числовым типом с таким же поведением, что и float64
, так что присваивание в предыдущем листинге по-прежнему работает.
Вы также можете добавить значения температуре и в общем использовать ее как тип float64
, как показано далее:
1 2 3 4 5 6 |
type celsius float64 const degrees = 20 var temperature celsius = degrees temperature += 10 |
Тип celsius
является уникальным типом, а не просто другим названием типа float64
. Подробнее о возможности использования других названий типов в статье о работе со строкам в Go. Однако здесь при попытке использовать float64
выйдет ошибка:
1 2 |
var warmUp float64 = 10 temperature += warmUp // Ошибка в операции: несовпадение типов |
При добавлении переменной warmUp
ее нужно конвертировать в тип celsius
. Такая версия действует:
1 2 |
var warmUp float64 = 10 temperature += celsius(warmUp) |
Возможность создания собственных типов может быть очень полезной для улучшения читабельности и качества кода. В следующем коде показано, что типы celsius
и fahrenheit
не могут сравниваться или объединяться:
1 2 3 4 5 6 7 8 9 10 11 |
type celsius float64 type fahrenheit float64 var c celsius = 20 var f fahrenheit = 20 // Ошибка в операции: несовпадение типов celsius и fahrenheit if c == f { } c += f |
Вопрос для проверки:
В чем преимущества объявления новых типов, таких как celsius
и fahrenheit
?
Создание своих собственных типов данных в Golang
В предыдущем разделе были объявлены типы celsius
и fahrenheit
, что привнесло в код понятие температуры, но опустило подробности касательно области хранения. Типы float64
или float32
мало что говорят о значении переменных температуры, в то время как типы celsius
, fahrenheit
и kelvin
передают нужный смысл.
После объявления типа его можно использовать везде, где вы будете использовать предварительно объявленные типы Go (int
, float64
, string
и так далее), включая параметры и результаты функции, как показано в следующем примере:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package main import "fmt" type celsius float64 type kelvin float64 // kelvinToCelsius converts °K to °C func kelvinToCelsius(k kelvin) celsius { return celsius(k - 273.15) // Необходима конвертация типа } func main() { var k kelvin = 294.0 // Аргумент должен быть типа kelvin c := kelvinToCelsius(k) fmt.Print(k, "° K is ", c, "° C") // Выводит: 294° K is 20.850000000000023° C } |
Функция 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
и так далее). Способ объявления типа нам уже известен:
1 |
type kelvin float64 |
Тип kelvin
обладает тем же поведением, что и базовый тип float64
. Вы можете складывать, умножать и осуществлять другие операции над значениями kelvin
, как с вещественными числами. Объявление метода для конвертации kelvin
в celsius
такое же простое, как и объявление функции. Они оба начинаются с ключевого слова func
и тело функции идентично телу метода:
1 2 3 4 5 6 7 |
func kelvinToCelsius(k kelvin) celsius { // функция kelvinToCelsius return celsius(k - 273.15) } func (k kelvin) celsius() celsius { // метод celsius для типа kelvin return celsius(k - 273.15) } |
Метод celsius
не принимает никаких параметров, но перед его названием значится что-то вроде параметра. Это приемник, как показано на схеме ниже. Методы и функции могут принимать много параметров, однако у методов также должен быть приемник. Внутри тела метода celsius приемник действует как и любой другой параметр.
Объявление метода
Синтаксис метода отличается от вызова функции:
1 2 3 4 5 |
var k kelvin = 294.0 var c celsius c = kelvinToCelsius(k) // Вызов функции kelvinToCelsius c = k.celsius() // Вызов метода celsius |
Методы вызываются вместе с точкой, что выглядит как вызов функции из другого пакета. Однако в данном случае за переменной верного типа следует точка и название метода.
Теперь, когда преобразование температуры является методом типа kelvin
, название вроде kelvinToCelsius
является излишним. В пакете может быть только одна функция с заданным названием, что должно отличаться от названия типа, поэтому функция celsius
, которая возвращает тип celsius
, невозможна. Однако каждый тип температуры может предоставить метод celsius
. К примеру, тип fahrenheit
может быть улучшен следующим образом:
1 2 3 4 5 6 |
type fahrenheit float64 // celsius converts °F to °C func (f fahrenheit) celsius() celsius { return celsius((f - 32.0) * 5.0 / 9.0) } |
Создается приятная симметрия, где у каждого типа температуры может быть метод celsius
для конвертации в градусы Цельсия.
Задание для проверки:
Идентифицируйте приемника в данной декларации метода: func (f fahrenheit) celsius() celsius
.
Заключение
- Объявление собственных типов может сделать код более читабельным и понятным;
- Методы подобны функциям, связанным с типом посредством указанного приемника
перед названием метода. Методы могут принимать несколько параметров и возвращать
несколько результатов, как и функции, но у них всегда должен быть один приемник. В теле метода приемник ведет себя так же, как и любой другой параметр; - В синтаксисе вызова метода используется точка с переменной подходящего типа, следующим за ней, названием метода и другими аргументами.
Итоговое задание для проверки:
Напишите программу с типами celsius
, fahrenheit
и kelvin
и методами для конвертации из одного типа температуры в другой.
Администрирую данный сайт с целью распространения как можно большего объема обучающего материала для языка программирования Go. В IT с 2008 года, с тех пор изучаю и применяю интересующие меня технологии. Проявляю огромный интерес к машинному обучению и анализу данных.
E-mail: vasile.buldumac@ati.utm.md
Образование
Технический Университет Молдовы (utm.md), Факультет Вычислительной Техники, Информатики и Микроэлектроники
- 2014 — 2018 Universitatea Tehnică a Moldovei, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Universitatea Tehnică a Moldovei, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»
Спасибо автору! Очень доходчиво, что не скажешь о других курсах!