Разработка и Конфигурация · 11 мин
Мутабельные значения в 1С: что это и как с ними работать
Что такое мутабельные значения в 1С, чем они отличаются от примитивных типов, как изменение объекта влияет на данные и каких ошибок избегать при разработке.
Мутабельным (изменяемым) называется значение, которое можно модифицировать после создания без порождения нового объекта. В контексте 1С этот термин чаще всего применяют к объектам встроенного языка и объектам метаданных: документам, справочникам, таблицам значений, массивам, структурам. Изменение реквизита объекта меняет сам объект, а все переменные, ссылающиеся на него, видят новое состояние.
Понимание мутабельности критично для разработчика 1С: от него зависит, как ведут себя данные при передаче в процедуры и функции, почему «внезапно» меняется таблица значений в вызывающем коде и почему запись объекта в базу может привести к конфликту блокировок. Ошибки в этой области — одна из частых причин трудноуловимых дефектов в конфигурациях.
Что такое мутабельность и какие типы в 1С изменяемы
Мутабельность — свойство типа данных. Если тип мутабелен, то операция изменения затрагивает сам объект в памяти, а не создаёт его копию. Если тип иммутабелен, любое «изменение» на самом деле создаёт новое значение, а старое остаётся нетронутым.
В 1С к мутабельным относятся:
- объекты базы данных: ДокументОбъект, СправочникОбъект, ПланСчетовОбъект и аналогичные;
- коллекции: Массив, ТаблицаЗначений, ДеревоЗначений, Структура, Соответствие, СписокЗначений;
- объекты формы: ДанныеФормыСтруктура, ДанныеФормыКоллекция;
- прочие прикладные объекты: Запрос, ПостроительОтчета, ТабличныйДокумент и т. п.
Иммутабельны примитивные типы: Число, Строка, Дата, Булево, Неопределено, NULL. Например, функция СтрЗаменить() не меняет исходную строку — она возвращает новую. А вот добавление строки в таблицу значений меняет именно существующую таблицу.
Передача по ссылке и по значению: где проявляется мутабельность
Главное практическое следствие мутабельности — поведение при передаче параметров в процедуры и функции. Мутабельные объекты передаются по ссылке: внутри вызванной процедуры работает тот же самый объект. Если процедура добавит строку в переданную таблицу значений, вызывающий код увидит эту строку.
Примитивные типы передаются по значению: процедура получает копию, и её изменения никак не влияют на исходную переменную. Модификатор Знач в объявлении параметра заставляет передать копию, но для сложных объектов его поведение ограничено — например, объекты базы данных через Знач не копируются в полном смысле.
Процедура ДобавитьСтроку(Таблица)
НоваяСтрока = Таблица.Добавить();
НоваяСтрока.Номенклатура = "Товар";
КонецПроцедуры
// После вызова исходная таблица уже содержит строку
ДобавитьСтроку(МояТаблица);
Если нужно защитить исходную коллекцию от изменений, создавайте копию явно: для таблицы значений — метод Скопировать(), для массива — перебор элементов в новый массив, для структуры — заполнение новой структуры.
Мутабельные объекты базы данных: ДокументОбъект и его жизненный цикл
Объект типа ДокументОбъект или СправочникОбъект — это мутабельное представление данных в памяти. Вы получаете объект через ПолучитьОбъект() по ссылке, меняете реквизиты, добавляете строки в табличные части — и все эти изменения существуют только в памяти до вызова метода Записать().
Это создаёт важное разделение: изменение объекта в памяти не меняет данные в базе. Обратное тоже верно: если два фрагмента кода получили объект одного и того же документа и оба вызвали Записать(), второй может получить ошибку из-за конфликта версий либо молча перезаписать чужие изменения — поведение зависит от режима и блокировок.
Типичный безопасный сценарий: получить объект, изменить, записать, освободить. Опасный сценарий: долго держать объект в памяти, передавать его между вызовами сервера и клиента, записывать после длительных вычислений — за это время данные в базе могли изменить другие пользователи.
Мутабельность в формах: ДанныеФормы и модифицированность
В управляемых формах данные реквизитов — тоже мутабельные объекты. Изменение реквизита формы программно или пользователем приводит к установке признака модифицированности: платформа отслеживает, что состояние формы отличается от сохранённого.
Практические следствия: программное заполнение табличной части в обработчике на сервере тоже «модифицирует» форму, и при закрытии пользователь получит вопрос о сохранении. Если это нежелательно, после программных изменений можно сбросить признак через Модифицированность = Ложь, но делать это нужно осознанно — иначе реальные изменения пользователя могут быть потеряны без предупреждения.
При передаче данных формы между клиентом и сервером платформа сериализует мутабельные структуры. Частые серверные вызовы с передачей больших таблиц заметно замедляют работу, поэтому объёмные изменения лучше выполнять целиком на сервере одним вызовом.
Признак проблемы с мутабельностью в форме — «плавающий» вопрос о сохранении при закрытии, хотя пользователь ничего не менял. Проверьте обработчики ПриСозданииНаСервере и ПриОткрытии: часто там программно изменяются реквизиты формы.
Типичные ошибки при работе с мутабельными значениями
Большинство дефектов связано с тем, что разработчик ожидает поведение «по значению» там, где работает ссылка на общий объект. Разберём характерные случаи.
Отдельный класс ошибок — кэширование мутабельных объектов в переменных модуля или параметрах сеанса. Объект, положенный «на память», может быть изменён любым последующим кодом, и найти источник изменения бывает очень трудно. Для кэшей безопаснее хранить копии или иммутабельные представления (например, сериализованные данные).
Как проверить поведение и отладить проблему
Если подозреваете, что данные меняются «сами собой», проверьте цепочку передачи объекта. Основной инструмент — отладчик: поставьте точку останова в месте создания коллекции и отслеживайте, в какие процедуры она передаётся.
- 1Найдите место создания объекта (таблицы, структуры, объекта документа) и зафиксируйте его состояние в отладчике.
- 2Проследите все вызовы, куда объект передаётся параметром, и проверьте, нет ли внутри них изменений.
- 3Проверьте, не сохраняется ли объект в реквизит формы, переменную модуля или параметр сеанса.
- 4Если объект менять нельзя — замените передачу на передачу копии и повторите сценарий.
- 5Проверьте результат: вызывающий код должен видеть исходное состояние коллекции после вызова процедуры.
Как проверить результат
Состав и содержимое строк не изменились, если процедура не должна их менять
Добавились или удалились строки, изменились значения колонок
Форма не спрашивает о сохранении, если пользователь ничего не вводил
Вопрос о сохранении появляется сразу после открытия
Запись проходит без ошибок блокировок при параллельной работе
Ошибки «Конфликт блокировок» или потеря чужих изменений
Когда выбирать копию, а когда работать по ссылке
Передача по ссылке — нормальный и эффективный механизм, отказываться от него не нужно. Копирование оправдано, когда вызываемый код не должен влиять на вызывающий, когда объект помещается в долгоживущее хранилище или когда обработка выполняется асинхронно.
Как выбрать действие
Что важно запомнить
Мутабельные значения в 1С — объекты, изменяемые по ссылке: документы, справочники, таблицы значений, массивы, структуры. Примитивные типы иммутабельны. Передача в процедуру идёт по ссылке, поэтому изменения видны вызывающему коду; если это нежелательно — передавайте копию. Для объектов базы данных сокращайте интервал между чтением и записью, чтобы избежать конфликтов при параллельной работе.
Частые вопросы о мутабельных значениях в 1С
Чем ссылка на документ отличается от объекта документа?
Ссылка (ДокументСсылка) — это иммутабельный идентификатор записи в базе: по ней можно читать реквизиты, но нельзя их менять. Объект (ДокументОбъект) — мутабельное представление в памяти, получаемое методом ПолучитьОбъект(); его реквизиты можно изменять, а изменения фиксируются в базе только после вызова Записать().
Почему строка в 1С считается иммутабельной?
Строковые функции встроенного языка (СтрЗаменить, Лев, СокрЛП и другие) возвращают новую строку, не меняя исходную. Переменная просто переназначается на новое значение. Поэтому строки безопасно передавать в процедуры — вызывающий код не пострадает.
Как правильно скопировать таблицу значений?
Используйте метод Скопировать() — он создаёт новую таблицу с той же структурой колонок и теми же строками. Для копирования только отобранных строк применяйте Скопировать() с параметром отбора. Учтите: если в колонках хранятся другие мутабельные объекты, они не клонируются — копируются только ссылки на них.
Можно ли передать мутабельный объект в фоновое задание?
Напрямую объекты вроде ТаблицаЗначений или ДокументОбъект в фоновое задание не передаются — параметры сериализуются, и поддерживаются ограниченные типы. Обычно передают примитивные данные, ссылки или помещают данные во временное хранилище, а в задание передают адрес хранилища.
Почему сравнение двух одинаковых таблиц даёт Ложь?
Оператор сравнения для объектов коллекций сравнивает ссылки, а не содержимое. Две таблицы с идентичными строками — разные объекты в памяти, поэтому результат — Ложь. Для сравнения содержимого нужно сравнивать колонки и построчно значения, либо сериализовать обе таблицы и сравнить результат.
Опасно ли хранить структуру в реквизите формы?
Сама по себе структура в реквизите формы допустима, но любой код, получивший к ней доступ, может её изменить, что влияет на модифицированность формы и усложняет отладку. Для служебных данных, которые не должны меняться пользователем, надёжнее хранить копию при выдаче наружу либо использовать реквизиты с ограниченным доступом через программный интерфейс формы.