0

Как использовать оператор Перейти?

Давайте проведем небольшой экскурс в историю. Откуда взялся оператор Перейти и почему вокруг него разразилась настоящая «священная война»? Почему количество противников этого оператора растет год от года и как слепая вера людей перечеркивает здравый смысл?
Любой процедурный язык программирования, вне зависимости от своего уровня, должен располагать средствами управления вычислениями. Как правило, это операторы условных вычислений, циклической обработки и безусловного перехода. Еще со времен языка ассемблера, в состав операторов языков программирования включался оператор безусловного перехода 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);
    
    ~Выход:
	
КонецПроцедуры//НайтиЗначениеВТаблице()

По моему мнению, аскетичность данного подхода налицо. Да и с эффективностью кода, тоже все в порядке.

В качестве домашнего задания, предлагаю Вам сравнить эти способы, найти отличия и ответить для себя на вопрос: «Когда можно использовать оператор Перейти?».

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *