Управление потоком
Мы уверенно движемся вперёд. Можно только позавидовать - впереди у нас много нового, неизведанного и удивительного. Любознательность, в определённой степени бескорыстная - в ней сущность нашего продвижения по ступенькам науки. Приступим!
Под управлением потоком мы будем понимать операторы ветвления и циклы, которые мы сейчас и разберём.
Начинать будем с отличий. Первое и основное, что нужно понимать по данной теме в языке Go - это отсутствие начисто таких конструкций, как while, do while, foreach. Весь ассортимент сведен к одному единственному оператору - for. Во-вторых, следует запомнить, что, в отличие от большинства С-подобных языков, в языке Go параметры цикла for и условия операторов ветвления никогда не берутся в круглые скобки! И, наконец, нужно не забывать семантическое значение переноса строки, фактически, замещающее собою применение точки с запятой (semicolon). Именно поэтому, возможна только нижеприведенная форма записи:
И будут всегда ошибочны любые другие формы:
Оператор for
Go - язык очень лаконичный и аккуратный. Поэтому отсутствие избыточности и разнообразия вполне в рамках его парадигмы. Отсутствие оператора while со товарищи с лихвой окупается полиморфностью оператора for.
Прежде всего, оператор for может принимать классическую форму:
Пожалуй, оператор for - один из немногих случаев массового применения точки с запятой (semicolon), тщательно избегаемой в языке Go.
Объявление переменной-счётчика можно при необходимости вынести за пределы конструкции, тем самым расширив её зону видимости. Не забудьте только сохранить точку с запятой в положенном ей месте.
А вот так for может мимикрировать под цикл while:
Обратите внимание, точки с запятой в данной ипостаси цикла for можно опустить, но их наличие не будет ошибкой.
И, наконец, бесконечный цикл:
В данной конструкции точки с запятой также можно опустить, либо же использовать по желанию, чего я делать не рекомендую. Меньше знаков - чище код. Обратите внимание, нам пришлось использовать оператор break для выхода из бесконечного цикла. В случае использования оператора for в форме бесконечного цикла, это - единственная возможность из такого цикла выйти. При использовании подпрограмм Go (горутин), то есть многопоточности, зачастую используют бесконечные циклы, работа которых заканчивается только тогда, когда программа завершает свою работу. Рядом с оператором break стоит оператор continue, который прерывает лишь текущую итерацию цикла. При этом оператор for переходит к следующей итерации, не прерывая своей работы.
Выведем только чётные числа:
Циклы могут быть вложенными, к примеру при работе с многомерными массивами или при решении специфических задач.
Выведем, к примеру, таблицу Пифагора:
Обратите внимание - \t - как и во множестве C-подобных языков - символ табуляции. Подобные символы, а также символы форматирования, так называемые "verbs" мы рассмотрим позднее в разделе, посвящённом работе с текстом.
И последнее о цикле for. При использовании с массивами, со срезами и отображениями, то есть с такими переменными, которые имеют свойство перечисляемости, цикл for имеет особую, дополнительную форму, которую можно в общем виде представить так:
Здесь range - ключевое слово. Имена же переменных key и value даны для наглядности и могут быть заменены любыми. Далее, для понимания происходящего, мы используем массив. Знаю, что не проходили. Да, обещаю вскоре исправиться.
Key можно опустить:
Такова форма, если нужно опустить value:
Не станем спорить о пользе бесконечного цикла по диапазону; выглядит он таким образом:
Операторы break и continue в цикле по диапазону остаются в прежней силе. Пожалуй, это исчерпывающая информация о цикле for.
Оператор goto
Коль скоро с оператором for мы расстались на ноте break и continue, перейдём по горячему следу к оператору goto. Как и в языке C, используется данный оператор совместно с метками. Синтаксис нехитрый:
Существует тривиальное утверждение, что использование оператора goto - дурной тон программирования. Автор вполне согласен с данным утверждением. Это приём, ведущий к плохой читаемости кода и неочевидности ветвлений управления потоком, замысла программиста. Если вы использовали данный оператор - остановитесь, размыслите. Чаще всего, вы сможете таким образом "перефразировать" ваш код, что позволит в конечном счёте избавиться от goto. Однако, это довольно "прилипчивый" оператор, и иногда цена избавления от него - также неудобочитаемый и неясный код. To be or not to be - решение остаётся за вами. Приведу здесь вполне правдоподобный пример использования оператора goto. Пускай это будет программа "ping". Используя пакет стороннего разработчика github.com/sparrc/go-ping, программа производит опрос хоста ipAddr. В случае неудачи, программа повторяет это действие трижды.
Для оживления изложения, добавлю сюда, пожалуй, пример решения задачки из leetcode. Задание таково:
Write a function to find the longest common prefix string amongst an array of strings. If there is no common prefix, return an empty string "".
Example 1:
Input: strs = ["flower","flow","flight"]
Output: "fl"
Example 2:
Input: strs = ["dog","racecar","car"]
Output: "" Explanation: There is no common prefix among the input strings.
Решение:
Решение достаточно оригинальное, и к тому же демонстрирует высокое сравнительное быстродействие.
If...else - неразлучная пара
Если излагать предмет в том порядке, как это обычно делают во всех пособиях, то именно с операторов if и else следовало начинать повествование в этой главе. Однако применение этих операторов в языке Go достаточно тривиально, что и натолкнуло автора на мысль начать рассказ именно с наиболее интересного - с ярких отличий. Однако, по ходу изложения, мы уже столь часто были вынуждены прибегнуть к использованию if...else, что разобрать данный предмет пришло, кажется, самое время.
Итак, приведём пример обычного использования оператора if:
Как обычно, оператор if дополняет комплиметнарный ему оператор else:
Следует отметить, что правило, касающееся семантического значения переносов строки, касается и употребления оператора else. Он сам, и его открывающая фигурная скобка, должны находиться в той же строке, что и закрывающая фигурная скобка предшествующего if. Все другие способы написания приведут вас к ошибке!
Как и во многих других языках, в Go допустима конструкция else if:
Блоков else if может быть в коде несколько.
Особым приёмом, отличительным для языка Go, является объявление переменных и использование выражений присваивания внутри оператора if:
Обратите внимание на использование точки с запятой внутри такого выражения. Данная форма записи - очень экономная; она компактна, а также ограничивает область видимости и время существования объявленной таким образом переменной границами текущего блока кода. В уместном случае, рекомендуется пользоваться данным приёмом.
Необходимо сказать несколько слов об идеологии использования в языке Go операторов if...else. Повторим, что сердцевина этого языка - компактность и краткость. Именно поэтому, хорошим тоном программирования на Go считается так компоновать свой код, чтобы максимально сокращать все выражения, использовать как можно меньшее количество ветвлений, а в идеале - единственный оператор if.
Хорошо:
А так лучше:
Также отметим, что чаще всего, цепочка ветвлений if...else той или иной длины чаще всего может быть заменена эквивалентным оператором switch. Перейдём к этому оператору.
Оператор switch
Особенностью оператора switch в языке Go, отличающей его, к примеру, от таких языков, как C/C++, C# и Java, является отсутствие так называемого "проваливания" от одного оператора case к другому. Закономерным следствием этого есть отсутствие необходимости использования оператора break в каждом кейсе. Как обычно, допускается и приветствуется использование заключительного default.
Пример обычного switch:
Чтобы сработал default:
Приведём более сложный пример (аргументом case является предикат):
Аргументом switch также может быть выражение:
После оператора case можно указывать несколько значений, разделённых запятыми:
Таким образом, мы рассмотрели все аспекты применения оператора switch.
Подытожим. На данный момент, мы изучили все операторы управления потоком в языке Go, за исключением оператора select, который является своеобразным аналогом оператора switch для так называемых каналов, к которым мы обратимся только при изучении многопоточности.
Раунд!
Last updated
Was this helpful?