В процессе разработки конфигураций на платформе 1С:Предприятие периодически возникает задача обмена значениями между двумя реквизитами одного объекта (например, справочника или документа). Это может потребоваться при реализации интерактивных функций на форме (например, при нажатии кнопки "Поменять местами"), перестановке приоритетов, исправлении ошибочно введенных пользователем данных или при программной обработке больших массивов информации.
На первый взгляд, задача кажется тривиальной и изучается на первых уроках программирования. Однако в среде 1С существует несколько подходов к её решению — от классических и безопасных до изящных платформенных методов и хитрых математических трюков. В этой статье мы подробно разберем каждый способ, проанализируем их достоинства, недостатки и скрытые угрозы, а также выясним, какое решение является наиболее предпочтительным с точки зрения стандартов разработки фирмы "1С".
Этот способ является самым простым, надежным и понятным для любого разработчика. Его суть заключается в создании третьей (буферной) переменной, которая временно сохраняет значение одного из реквизитов, предотвращая его потерю при перезаписи.
Давайте посмотрим на пример реализации этого алгоритма в модуле формы или объекта:
// Сохраняем значение первого реквизита во временную переменную
ВременныйРеквизит = Объект.Реквизит1;
// Переносим значение второго реквизита в первый
Объект.Реквизит1 = Объект.Реквизит2;
// Записываем сохраненное значение из временной переменной во второй реквизит
Объект.Реквизит2 = ВременныйРеквизит;
Проанализируем ситуацию и выделим ключевые преимущества данного подхода:
В реальной коммерческой разработке этот способ признан стандартом де-факто и рекомендуется к использованию в 99% случаев.
В платформе 1С существует замечательный встроенный механизм — функция ЗаполнитьЗначенияСвойств. Она позволяет сопоставлять свойства источника и приемника по их именам и копировать данные. Используя этот механизм совместно с объектом Структура, мы можем решить задачу обмена значениями буквально в одну строку кода без явного объявления промежуточных переменных в тексте программы.
Рассмотрим подробнее этот красивый прием:
ЗаполнитьЗначенияСвойств(Объект, Новый Структура("Реквизит1, Реквизит2", Объект.Реквизит2, Объект.Реквизит1));
Разберем по шагам, как работает этот элегантный алгоритм:
Новый Структура создает в оперативной памяти временный вспомогательный объект. Мы передаем в него строку с именами будущих свойств ("Реквизит1, Реквизит2") и соответствующие им значения. Обратите внимание на порядок передачи параметров: свойству структуры с именем Реквизит1 мы присваиваем текущее значение Объект.Реквизит2, а свойству структуры Реквизит2 — значение Объект.Реквизит1. Таким образом, в структуре происходит виртуальный обмен значений.ЗаполнитьЗначенияСвойств. В качестве первого параметра (приемника) мы передаем наш Объект (например, справочник), а в качестве второго (источника) — только что созданную структуру.Этот способ невероятно удобен, когда вам нужно поменять местами значения не двух, а сразу целой группы реквизитов. Кроме того, он полностью универсален по отношению к типам данных.
Этот способ часто встречается в качестве логической задачи на собеседованиях для начинающих программистов. Его цель — проверить понимание базовой арифметики и умение работать с памятью без выделения дополнительных переменных. Алгоритм применим исключительно для числовых типов данных.
Давайте разберем этот алгоритм, основанный на сложении и вычитании:
Объект.Реквизит1 = Объект.Реквизит1 + Объект.Реквизит2;
Объект.Реквизит2 = Объект.Реквизит1 - Объект.Реквизит2;
Объект.Реквизит1 = Объект.Реквизит1 - Объект.Реквизит2;
На первый взгляд математика работает безупречно. Однако при внедрении такого кода в реальную рабочую базу 1С разработчик неизбежно столкнется с серьезными подводными камнями:
Объект.Реквизит1 + Объект.Реквизит2 итоговая сумма превысит максимально допустимую длину поля. Платформа 1С либо выдаст критическую ошибку переполнения, либо принудительно обрежет разряды числа. В результате данные будут безвозвратно испорчены.
Объект.Реквизит1 = Объект.Реквизит1 * Объект.Реквизит2;
Объект.Реквизит2 = Объект.Реквизит1 / Объект.Реквизит2;
Объект.Реквизит1 = Объект.Реквизит1 / Объект.Реквизит2;
Division by zero).Вывод: Использовать математические трюки в промышленном коде 1С крайне не рекомендуется из-за рисков потери данных и нестабильной работы программы.
Если перед вами стоит жесткое условие — поменять местами значения двух текстовых (строковых) реквизитов, не используя при этом промежуточные переменные и сторонние объекты (структуры), можно прибегнуть к строковой конкатенации и последующему вырезанию подстрок с помощью встроенных функций платформы 1С.
Давайте посмотрим на пример реализации такого алгоритма:
// Принудительно приводим значения к строковому типу (для безопасности)
Строка1 = Строка(Объект.Реквизит1);
Строка2 = Строка(Объект.Реквизит2);
// Шаг 1: Объединяем две строки в одну сквозную строку
Строка1 = Строка1 + Строка2;
// Шаг 2: Извлекаем из левой части объединенной строки исходное значение Строка1
// Длина извлекаемой части равна разности полной длины новой строки и длины Строка2
Строка2 = Лев(Строка1, СтрДлина(Строка1) - СтрДлина(Строка2));
// Шаг 3: Вырезаем из остатка строки исходное значение Строка2
Строка1 = Сред(Строка1, СтрДлина(Строка2) + 1);
// Записываем полученные результаты обратно в реквизиты объекта
Объект.Реквизит1 = Строка1;
Объект.Реквизит2 = Строка2;
Этот алгоритм наглядно демонстрирует возможности работы со строковыми функциями 1С, такими как Лев, Сред и СтрДлина. Тем не менее, он обладает теми же недостатками, что и математический способ: код сложен для быстрого чтения и понимания другими разработчиками, а также требует дополнительных ресурсов процессора на постоянное преобразование, конкатенацию и парсинг текстовых строк.
Подводя итог нашему анализу, сопоставим все рассмотренные методы в единую систему рекомендаций:
ЗаполнитьЗначенияСвойств). Это стандартный и очень изящный прием в духе платформы 1С.