Давайте проведем небольшой экскурс в историю. Откуда взялся оператор Перейти
и почему вокруг него разразилась настоящая «священная война»? Почему количество противников этого оператора растет год от года и как слепая вера людей перечеркивает здравый смысл?
Любой процедурный язык программирования, вне зависимости от своего уровня, должен располагать средствами управления вычислениями. Как правило, это операторы условных вычислений, циклической обработки и безусловного перехода. Еще со времен языка ассемблера, в состав операторов языков программирования включался оператор безусловного перехода Goto, который позволял немедленно передать управление оператору, расположенному в другом месте программы. Ровно с тех пор программисты всех мастей ходили по граблям: метки были раскиданы по всему коду, а переход можно было выполнить даже внутрь тела цикла или, даже, другой процедуры. Такой вариант незащищенного кодинга превращал незатейливую отладку в ночной кошмар.
В борьбе между развитием интеллектуальных средств синтаксического контроля и административным ресурсом, победил последний: было принято решение искоренить оператор Goto из кода и заменить его альтернативными вычислениями. Для написанного кода даже появился критерий оценки качества: это значение, обратно пропорциональное количеству операторов goto в коде. Забавно, не правда ли!?
Не смотря на все административные запреты, оператор Goto перекочевывал из одного языка программирования в другой. Из десятилетия в десятилетие, уровень языков рос, а вместе с ними росли средства синтаксического контроля, которые стали выявлять потенциальные ошибки еще на этапе компиляции. К большому сожалению, эта новость обошла стороной и административный ресурс, и староверов-программистов. В итоге, при развитых средствах разработки, большинство из них продолжает изобретать колесо.
Такими средствами, кстати, обладает и встроенный язык 1С:Предприятие, начиная с версии 7.7. С помощью оператора Перейти нельзя передать управление на оператор, расположенный в другом модуле, в другой процедуре или внутри тела цикла. Я соглашусь, что нет кода, который нельзя было бы переписать без оператора Перейти
. Но делается это, в большинстве случаев, в ущерб читаемости и эффективности кода. Давайте рассмотрим это на примере поиска ячейки в таблице, содержащей необходимый текст.
1. Выход из вложенного цикла с помощью промежуточной переменной
Это самый простой способ реализации, который придет в голову «гоутуфобу»: использовать для прерывания внешнего цикла промежуточную переменную (в моем примере это НайденноеЗначение)
. Если во вложенном цикле переменная будет инициализирована, внешний цикл будет прерван.
Процедура НайтиЗначениеВТаблице(Таб) СтрокаДляПоиска = ""; Если (ВвестиСтроку(СтрокаДляПоиска, "Что ищем?", 2) = 0) ИЛИ (СтрокаДляПоиска = "") Тогда Предупреждение("Нужно ввести значение!", 5); Возврат; КонецЕсли; НайденноеЗначение = ""; //поиск значения в таблице Для НомерСтроки = 1 По Таб.ВысотаТаблицы() Цикл Для НомерКолонки = 1 По Таб.ШиринаТаблицы() Цикл Если Таб.Область(НомерСтроки, НомерКолонки).Текст = СокрЛП(СтрокаДляПоиска) Тогда НайденноеЗначение = Шаблон("R[НомерСтроки]C[НомерКолонки]"); Прервать;//вернемся на уровень выше КонецЕсли; КонецЦикла; Если НЕ (НайденноеЗначение = "") Тогда Прервать;//выйдем из цикла КонецЕсли; КонецЦикла; Если (НайденноеЗначение = "") Тогда Предупреждение("Значение не найдено!", 5); Иначе Предупреждение("Значение найдено " + НайденноеЗначение, 5); КонецЕсли; КонецПроцедуры //НайтиЗначениеВТаблице()
К недостаткам такого способа можно отнести низкую читаемость кода и его запутанность. Ситуация еще более усугубляется при росте уровня вложенности циклов. «Гоутуфобам»приходится выбирать между слепой верой в запреты и читаемостью кода.
2. Выход из вложенного цикла с помощью вспомогательных функций
Вложенный цикл здесь перенесен в отдельную функцию. В основном же цикле достаточно проверить значение, возвращаемое функцией.
Процедура НайтиЗначениеВСтрокеТаблицы(Таб, НомерСтроки, СтрокаДляПоиска) Далее Процедура НайтиЗначениеВТаблице(Таб) СтрокаДляПоиска = ""; Если (ВвестиСтроку(СтрокаДляПоиска, "Что ищем?", 2) = 0) ИЛИ (СтрокаДляПоиска = "") Тогда Предупреждение("Нужно ввести значение!", 5); Возврат; КонецЕсли; //поиск значения в таблице Для НомерСтроки = 1 По Таб.ВысотаТаблицы() Цикл НайденноеЗначение = НайтиЗначениеВСтрокеТаблицы(Таб, НомерСтроки, СтрокаДляПоиска); Если НЕ (НайденноеЗначение = "") Тогда Предупреждение("Значение найдено " + НайденноеЗначение, 5); Возврат; КонецЕсли; КонецЦикла; Предупреждение("Значение не найдено!", 5); КонецПроцедуры //НайтиЗначениеВТаблице() Процедура НайтиЗначениеВСтрокеТаблицы(Таб, НомерСтроки, СтрокаДляПоиска) Для НомерКолонки = 1 По Таб.ШиринаТаблицы() Цикл Если Таб.Область(НомерСтроки, НомерКолонки).Текст = СокрЛП(СтрокаДляПоиска) Тогда Возврат Шаблон("R[НомерСтроки]C[НомерКолонки]"); КонецЕсли; КонецЦикла; КонецПроцедуры //НайтиЗначениеВСтрокеТаблицы()
К недостаткам данного подхода можно отнести дополнительные накладные расходы, связанные с вызовом вложенных функций. Здесь «гоутуфобы» выбирают между слепой верой в запреты и эффективностью кода.
3. Выход из вложенного цикла с помощью оператора Перейти
Процедура НайтиЗначениеВТаблице(Таб) СтрокаДляПоиска = ""; Если (ВвестиСтроку(СтрокаДляПоиска, "Что ищем?", 2) = 0) ИЛИ (СтрокаДляПоиска = "") Тогда Предупреждение("Нужно ввести значение!", 5); Возврат; КонецЕсли; //поиск значения в таблице Для НомерСтроки = 1 По Таб.ВысотаТаблицы() Цикл Для НомерКолонки = 1 По Таб.ШиринаТаблицы() Цикл Если Таб.Область(НомерСтроки, НомерКолонки).Текст = СокрЛП(СтрокаДляПоиска) Тогда Предупреждение(Шаблон("Значение найдено R[НомерСтроки]C[НомерКолонки]"), 5); Перейти ~Выход; КонецЕсли; КонецЦикла; КонецЦикла; Предупреждение("Значение не найдено!", 5); ~Выход: КонецПроцедуры //НайтиЗначениеВТаблице()
По моему мнению, аскетичность данного подхода налицо. Да и с эффективностью кода, тоже все в порядке.
В качестве домашнего задания, предлагаю Вам сравнить эти способы, найти отличия и ответить для себя на вопрос: «Когда можно использовать оператор Перейти?».