Создание функций в Golang

Под конец данного урока вы сможете:

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

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

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

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

Go на Форум

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

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

Go в ВК Go в Telegram

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

Познакомившись с синтаксисом создания функций, мы напишем функции для программы анализа погоды. Станция экологического мониторинга Ровер (REMS) собирает данные о погоде на поверхности Марса. Мы создадим функции, что в теории могли бы стать частью программы REMS — к примеру, конвертер температуры.

Рассмотрим ситуацию, когда вам нужно сделать бутерброд. Кажется, будто это просто, но все-таки процесс готовки строится из нескольких этапов. Помыть овощи, нарезать все ингредиенты и так далее. Если вдаваться в более глубокие детали, можно упомянуть сбор пшеницы, превращение ее в муку и выпечку хлеба. Однако данные подготовительные функции вас не касаются, они являются частью работы фермера и пекаря.

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

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

Объявление функции в Golang

В документации Go значится список функций, что объявляются в каждом пакете стандартной библиотеки. Функций довольно много, и охватить их все в одном уроке просто невозможно.

Для использования функций в своем проекте вам часто придется сверяться с документацией, чтобы посмотреть, как именно объявлять и вызывать функцию. Изучив объявления для Intn, Unix, Atoi, Contains и Println, вы сможете использовать полученные знания для работы с другими функциями и написания своих собственных.

В одном из предыдущих уроков мы уже использовали функцию Intn для генерации псевдослучайных чисел. Перейдите на следующую страницу документации, найдите пакет math/rand и функцию Intn. Для нахождения Intn можете использовать их поиск по сайту.

Объявление Intn из пакета rand выглядит следующим образом:

Освежим в памяти способ использования функции Intn:

На следующей схеме части объявления идентифицируются, как и синтаксис для вызова функции Intn. Ключевое слово func позволяет Go понять о том, что это объявление функции. Название самой функции, Intn, должно начинаться с большой буквы.

объявление функции

Объявление и вызов функции Intn

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

Функция Intn принимает один параметр, что заключен в скобки. Параметром является название переменной, затем указывается тип и объявляется переменная:

При объявлении функции Intn целое число 10 передается в качестве единственного аргумента, он также заключается в скобки. Аргумент соответствует ожиданиям параметра Intn. Если аргумент не передается или не относится к типу int, компилятор Go сообщит об ошибке.

На заметку: Параметр и аргумент являются математическими терминами, но есть небольшое различие. Функция принимает параметры и вызывается с аргументами, хотя в некоторых случаях данные термины используются как взаимозаменяемые.

Функция Intn возвращает один результат, что является псевдослучайным целым числом типа int. Результат передается назад вызывающему, где используется для инициализации вновь объявленной переменной num.

Функция Intn принимает только один параметр. Однако функции могут принимать и несколько параметров, если их представить в виде списка, где параметры разделены запятыми. Функция Unix из пакета time принимает два параметра int64, что соответствуют количеству секунд и наносекунд, прошедших с 1 Января 1970 года. В соответствии с документацией, объявление будет выглядеть следующим образом:

Далее дан пример вызова функции Unix с двумя аргументами, что соответствуют параметрам sec и nsec:

Unix возвращает результат типа Time. Тип назначается автоматически, поэтому в коде, вызывающем Unix, тип результата уточнять не требуется, что привело бы к лишней многословности.

На заметку: В следующем уроке мы рассмотрим способы объявления новых типов вроде time.Time и big.Int.

Пакет time объявляет и экспортирует тип Time, что начинается с большой буквы, как и функция Unix. Использование верхнего регистра указывает на экспорт, следовательно, тип Time доступен из других пакетов.

Функция Unix принимает два параметра одинакового типа:

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

Возможен сокращенный вариант, но он может быть использовать где-то еще. К примеру, в функции Contains пакета strings, что принимает два параметра типа string:

На заметку: В документации Go иногда даются небольшие примеры, в которые можно добавить нужные вам детали. Дополнительные примеры также можно найти на gobyexample.com. Если вы уже работаете над собственными проектами, данные примеры могут прийтись кстати.

Во многих языках программирования есть функции, что принимают несколько параметров, однако Go также возвращает несколько результатов. Рассмотренная в одном из предыдущих уроков функция Atoi конвертирует строку в число и возвращает два результата, что в следующем примере присваиваются переменным countdown и err:

В документации для пакета strconv функция Atoi объявляется следующим образом:

Обратите внимание, что тип error является встроенным типом для указания ошибок.

С самого начала изучения Golang мы использовали функцию Println. Это универсальная функция в том плане, что она может принимать как один, так и несколько параметров. Она также принимает параметры разных типов, включая целые числа и строки:

Объявление функции из документации, может показаться несколько странным, так как здесь используются некоторые аспекты, которые мы еще не изучали:

Функция Println принимает один параметр а, но вы уже видели, что передача нескольких аргументов также возможна. Кроме того, вы можете передать функции Println переменное количество аргументов, на данную особенность указывает многоточие (...). Для этого есть специальный термин — вариативная функция, которой является Println. Параметр а является набором аргументов, передаваемых функции. О вариативных функциях более детально поговорим в одном из следующих уроков.

Типом параметра а является interface{}, что называют пустым типом интерфейса. Это специальный тип, что позволяет Println принимать int, float64, string, time.Time и другие типы без того, чтобы компилятор Go не выводил ошибку.

Комбинация вариативных функций и пустого интерфейса, написанная как …interface{}, значит, что вы передаете функции Println любое число аргументов любого типа. Все передаваемые данные отображаются без проблем.

На заметку: Все это время мы игнорировали два результата, что возвращает Println. Однако игнорирование ошибок в программировании считается дурным тоном. Подробнее об этом в уроке по обработке ошибок.

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

  1. Для вызова функции вы используете аргументы или параметры?
  2. Функция принимает аргументы или параметры?
  3. Чем функция, названием которой начинается с большой буквы (Contains) отличается от той, что пишется с маленькой буквы (contains)?
  4. На что указывает многоточие (…) при объявлении функции?

Создание функции в Golang

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

Данные сенсора температуры должны быть получены в единицах измерения, понятных для землян. Сенсоры считывают температуры по шкале Кельвина, где 0° K является абсолютным нулем, или минимальной возможной температурой. Функция в следующем листинге конвертирует температуру из градусы Кельвина в градусы Цельсия. После создания, функция может использоваться вновь, когда потребуется конвертация температуры.

Здесь функция kelvinToCelsius принимает один параметр под названием k типа float64. В соответствии правилами Go, первый комментарий для функции kelvinToCelsius начинается с названием функции, за которым следует описание того, что она делает.

Функция возвращает значение типа float64. Результат вычисления возвращается вызывающему с ключевым словом return, который потом используется для инициализации новой переменной celsius в внутри функции main.

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

Преимущества изоляции функции в Golang

Функция kelvinToCelsius из Листинга 1 изолирована от других функций. Ее единственной входной информацией является принимаемый параметр, а единственным выводом является возвращаемый результат. Он не вносит изменения во внешнее состояние программы. У таких функций нет побочных эффектов, они являются наиболее простыми для понимания, проверки и повторного использования.

Функция kelvinToCelsius модифицирует переменную k, однако k и kelvin полностью независимые переменные, поэтому присваивание нового значения к k внутри функции не оказывает никакого влияния на переменную kelvin внутри main. Такое поведение называется передачей значения, так как параметр k инициализируется через значение аргумента kelvin. Передача значения закрепляет границы перед функциями, помогая изолировать одну функцию от другой.

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

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

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

В чем преимущества разделения кода на функции?

Заключение

  1. Функции объявляются с названием, списком параметров и списком результатов;
  2. Названия функций и типов, что начинаются с большой буквы, делают их доступными для других пакетов;
  3. За каждым названием параметра или результата следует тип, хотя типы могут опускаться, когда у нескольких именованных параметров или результатов одинаковый тип. Результаты также могут быть представлены как типы без названий в списке;
  4. В вызовах функции есть префиксы с названием пакета, где объявляется функция, пока данная функция объявляется внутри того же пакета, откуда вызывается;
  5. Функции вызываются с аргументами, что соответствуют тем параметрам, что они принимают. Результаты возвращаются вызывающему с ключевым словом return.

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

Используйте Go Playground и модифицируйте Листинг 1 для добавления дополнительных функций конвертирования температуры:

  • Повторно используйте функцию kelvinToCelsius для конвертации 233° К в градусы Цельсия;
  • Напишите и используйте функцию конвертации температуры в градусы ФаренгейтаcelsiusToFahrenheit. Формула для конвертации температуры в градусы по Фаренгейту: (c * 9.0 / 5.0) + 32.0;
  • Напишите функцию kelvinToFahrenheit и проверьте, чтобы она конвертирова 0° К в приблизительно –459.67° F.

Вы использовали kelvinToCelsius и celsiusToFahrenheit в своей новой функции или написали независимую функцию с новой формулой? Оба подхода подойдут.

Понравилась статья?

Поддержи наш проект, чтобы мы могли создать больше хорошего контента!