В процессе отладки кода 1С часто возникает ситуация, когда мы останавливаемся на строке КонецФункции. Если функция содержит несколько операторов Возврат в разных ветках условных конструкций, становится неочевидно, какое именно значение будет возвращено в вызывающий код. Проходить весь путь отладки заново или гадать — неэффективно. Разберем несколько способов, как быстро и точно определить возвращаемое значение.
Проанализируем исходную ситуацию. У нас есть функция, которая в зависимости от типа переданного параметра возвращает разные значения:
Функция КлючЗадания(п_Задание) Экспорт
Если ТипЗнч(п_Задание)=Тип("ОбъектМетаданных") Тогда
л_Задание = РегламентныеЗадания.НайтиПредопределенное(п_Задание);
Если л_Задание=Неопределено Тогда
Возврат п_Задание.Ключ; // Ключ, заданный в метаданных.
Иначе
Возврат л_Задание.Ключ; // Ключ, заданный в регламентном задании.
КонецЕсли;
ИначеЕсли ТипЗнч(п_Задание)=Тип("РегламентноеЗадание") Тогда
Возврат п_Задание.Ключ; // Ключ, заданный в регламентном задании.
Иначе // Строка
Возврат п_Задание;
КонецЕсли;
КонецФункции
Задача — находясь на строке КонецФункции, понять, какой из операторов Возврат сработал и что именно вернется. Рассмотрим три подхода: от самого быстрого до наиболее правильного с точки зрения стандартов разработки.
Самый очевидный способ, предложенный на форуме, — это просто завершить выполнение текущей функции и посмотреть на результат в месте ее вызова.
КонецФункции, нажмите Shift+F11 ("Выйти из процедуры/функции"). Отладчик переместит вас в ту строку кода, откуда была вызвана ваша функция.
// После нажатия Shift+F11 отладчик вернется сюда,
// и вы сможете легко увидеть значение переменной "МойКлюч"
МойКлюч = КлючЗадания(ТекущееЗадание);
// Отладчик вернется сюда, но явного значения вы не увидите.
// Вам придется вычислять выражение, чтобы понять, что вернулось.
Если КлючЗадания(ТекущееЗадание) = "НужныйКлюч" Тогда
// ...
КонецЕсли;
Также может быть полезен инструмент "Стек вызовов". Он показывает последовательность вызовов, которая привела к текущей точке, и позволяет быстро перемещаться между ними. Однако он не покажет возвращаемое значение до фактического выхода из функции.
Это более изящный метод, который позволяет узнать результат, не выходя из текущей функции. Он идеально подходит для функций, которые не меняют состояние системы (не записывают данные в базу, не изменяют глобальные переменные).
Функции, которые при одинаковых входных параметрах всегда возвращают один и тот же результат и не имеют побочных эффектов, называются идемпотентными или "чистыми". Наша функция КлючЗадания как раз такая — она только читает данные. Для таких функций этот способ безопасен и очень удобен.
Разберем по шагам:
КонецФункции), откройте окно "Табло". Это можно сделать через меню "Отладка" -> "Табло" или нажав Shift+F9.КлючЗадания(п_Задание).Важное предостережение: Не используйте этот метод для функций, которые что-то изменяют! Например, если функция создает и записывает документ, повторный вызов в "Табло" приведет к созданию дубля этого документа, что может нарушить данные в базе.
Наличие множественных операторов Возврат усложняет не только отладку, но и чтение и дальнейшую поддержку кода. Согласно стандартам разработки 1С, рекомендуется стремиться к тому, чтобы у функции была только одна точка выхода.
Идея проста: мы заводим локальную переменную для хранения результата, во всех ветках кода присваиваем значение этой переменной, а в самом конце функции возвращаем ее.
Посмотрим, как преобразится наш исходный код:
Функция КлючЗадания(п_Задание) Экспорт
// 1. Объявляем переменную для результата
Перем ВозвращаемоеЗначение;
Если ТипЗнч(п_Задание)=Тип("ОбъектМетаданных") Тогда
л_Задание = РегламентныеЗадания.НайтиПредопределенное(п_Задание);
Если л_Задание=Неопределено Тогда
// 2. Вместо "Возврат" присваиваем значение переменной
ВозвращаемоеЗначение = п_Задание.Ключ; // Ключ, заданный в метаданных.
Иначе
ВозвращаемоеЗначение = л_Задание.Ключ; // Ключ, заданный в регламентном задании.
КонецЕсли;
ИначеЕсли ТипЗнч(п_Задание)=Тип("РегламентноеЗадание") Тогда
ВозвращаемоеЗначение = п_Задание.Ключ; // Ключ, заданный в регламентном задании.
Иначе // Строка
ВозвращаемоеЗначение = п_Задание;
КонецЕсли;
// 3. Единственная точка выхода в конце функции
Возврат ВозвращаемоеЗначение;
КонецФункции
Какие преимущества мы получаем?
Возврат ВозвращаемоеЗначение;. В этой точке вы всегда гарантированно увидите итоговый результат, который вернет функция, просто наведя на переменную ВозвращаемоеЗначение.Возврат.Современные среды разработки, такие как 1C:EDT, часто содержат инструменты автоматического рефакторинга, которые могут преобразовать функцию с множественными выходами в функцию с одним выходом за пару кликов.
В итоге, хотя быстрые "трюки" вроде использования "Табло" полезны в моменте, приведение кода в соответствие со стандартами является лучшей долгосрочной инвестицией в его надежность и поддерживаемость.