Структура 1С — коллекция пар «ключ — значение», где ключ — строка по правилам имени переменной, а значение может быть любым: число, ссылка, массив, другая структура. Она есть в любой конфигурации на платформе 8.3 и работает одинаково на клиенте и на сервере. Ниже — конструктор с ключами, методы Вставить, Свойство и Удалить, обход, правила для имён ключей, приём «структура как набор параметров» с готовым общим модулем и типичные ошибки с текстами платформы.
К значению структуры обращаются через точку, как к реквизиту объекта: Товар.Цена. Поэтому её берут, когда набор полей известен заранее и несколько значений нужно передать одной переменной. Типичные места в коде:
ОткрытьФорму();ТаблицаЗначений.НайтиСтроки(Новый Структура("Склад", Склад));ОбщегоНазначения.ЗначенияРеквизитовОбъекта() в конфигурациях на БСП;ПрочитатьJSON() по умолчанию превращает объект JSON в структуру;Регистр букв в ключе не важен: Товар.цена и Товар.ЦЕНА — одно и то же поле.
// Пустая структура: ключи добавляются позже
Настройки = Новый Структура;
// Ключи через запятую, значения - следующими параметрами в том же порядке
Товар = Новый Структура("Артикул, Наименование, Цена", "A-100", "Болт М8", 12.5);
// Значения не переданы: все три ключа равны Неопределено
Отбор = Новый Структура("Номенклатура, Склад, Период");
// Структура внутри структуры
Заказ = Новый Структура("Номер, Покупатель", "0001", Новый Структура("ИНН, Телефон", "", ""));
Заказ.Покупатель.Телефон = "+7 900 000-00-00";
Первый параметр конструктора — строка с ключами через запятую, пробелы после запятых допустимы. Следующие параметры — значения в том же порядке: так структуру создают и сразу заполняют значениями одной строкой. Ключи, для которых значение не передали, получают Неопределено. Такая запись удобна для коротких структур из двух-четырёх полей. Когда полей больше, читаемее создать пустую структуру и добавлять ключи по одному через Вставить: сразу видно, какое значение к какому ключу относится.
Параметры = Новый Структура;
Параметры.Вставить("Количество", 10); // ключа не было - добавится
Параметры.Вставить("Количество", 15); // ключ уже есть - значение заменится, ошибки нет
Параметры.Количество = 20; // присваивание: только для существующего ключа
Параметры.Вставить("Комментарий"); // ключ со значением Неопределено
// Имя ключа в переменной
ИмяКлюча = "Склад";
Параметры.Вставить(ИмяКлюча, "Основной");
Параметры.Цена = 100; // Ошибка: Поле объекта не обнаружено (Цена)
Метод Вставить(Ключ, Значение) добавляет ключ, а если такой ключ уже есть — молча заменяет значение. Второй параметр необязателен: без него ключ появится со значением Неопределено. Присваивание через точку работает только для существующего ключа: нового поля оно не создаёт, а завершается ошибкой. Сводка по всем операциям:
| Операция | Ключа нет | Ключ есть |
|---|---|---|
С.Вставить("К", З) | добавляет ключ | заменяет значение |
С.К = З, С["К"] = З | ошибка «Поле объекта не обнаружено» | заменяет значение |
З = С.К, З = С["К"] | ошибка «Поле объекта не обнаружено» | возвращает значение |
С.Свойство("К", З) | Ложь | Истина, значение — в З |
С.Удалить("К") | ничего не делает | удаляет ключ |
Товар = Новый Структура("Артикул, Цена", "A-100", 1250);
Цена = Товар.Цена; // имя ключа известно при написании кода
ИмяПоля = "Артикул";
Артикул = Товар[ИмяПоля]; // имя ключа приходит в переменной
// Простая проверка наличия ключа
Если Товар.Свойство("Цена") Тогда
Сообщить("Цена указана");
КонецЕсли;
// Необязательный ключ: проверка и чтение за одно обращение
Скидка = Неопределено;
Если Не Товар.Свойство("Скидка", Скидка) Тогда
Скидка = 0; // ключа нет - берём умолчание
КонецЕсли;
Точка подходит, когда имя ключа известно при написании кода. Если имя приходит в переменной — например, вы перебираете список полей из настройки, — нужны квадратные скобки: Товар[ИмяПоля]. Запись Товар.ИмяПоля ищет ключ с буквальным именем «ИмяПоля», а не значение переменной.
Метод Свойство(Ключ, НайденноеЗначение) — безопасная проверка: он возвращает Истина или Ложь и не вызывает ошибку при отсутствии ключа. Второй параметр выходной: в него попадает значение, если ключ найден. Не рассчитывайте, что без ключа переменная сохранит прежнее содержимое, — присваивайте умолчание после проверки, как в примере. И помните: Свойство() проверяет наличие ключа, а не заполненность. Ключ со значением Неопределено тоже даст Истина.
Данные = Новый Структура("Код, Наименование, Комментарий", "001", "Болт М8", Неопределено);
// Обход: каждый ЭлементСтруктуры имеет тип КлючИЗначение
Для Каждого ЭлементСтруктуры Из Данные Цикл
Сообщить(ЭлементСтруктуры.Ключ + " = " + Строка(ЭлементСтруктуры.Значение));
КонецЦикла;
// Удаляем ключи со значением Неопределено: сначала собираем, потом удаляем
КУдалению = Новый Массив;
Для Каждого ЭлементСтруктуры Из Данные Цикл
Если ЭлементСтруктуры.Значение = Неопределено Тогда
КУдалению.Добавить(ЭлементСтруктуры.Ключ);
КонецЕсли;
КонецЦикла;
Для Каждого ИмяКлюча Из КУдалению Цикл
Данные.Удалить(ИмяКлюча);
КонецЦикла;
Сообщить(Строка(Данные.Количество())); // 2
Данные.Очистить(); // ключей не осталось, Количество() = 0
При обходе Для Каждого каждый элемент структуры имеет тип КлючИЗначение с двумя свойствами: Ключ и Значение. Оба доступны только для чтения. Чтобы поменять значение, пишите в саму структуру: Данные[ЭлементСтруктуры.Ключ] = НовоеЗначение.
Добавлять и удалять ключи внутри цикла по той же структуре нельзя: коллекция меняется прямо во время обхода. Поэтому в примере ключи сначала собраны в массив, а удаление идёт вторым циклом. Удалить() убирает пару целиком, Количество() возвращает число ключей, Очистить() удаляет всё сразу. Пустую структуру проверяют условием Количество() = 0.
На практике элементы обходятся в порядке добавления, но документация этого не обещает. Если порядок важен — колонки файла, поля выгрузки, — храните его отдельно массивом ключей.
Ключ подчиняется тем же правилам, что имя переменной: начинается с буквы или подчёркивания, дальше идут буквы, цифры и подчёркивание. Кириллица и латиница допустимы, можно смешивать. Пробел, дефис, точка, пустая строка или цифра в начале приводят к ошибке «Задано неправильное имя атрибута структуры» — и в Вставить(), и в конструкторе.
ИНН, _Служебный, Item2, ДатаДокумента.2024, order-id, Полное имя, Товар.Цена.Если ключи берутся из данных — артикулы, коды, GUID, поля JSON с дефисами, — структура не подходит в принципе. Для этого есть соответствие: его ключом может быть любая строка, число, дата или ссылка.
Самое полезное применение структуры — настройки процедуры. Вместо вызова Выгрузить(Склад, Истина, Ложь, 500, ""), где через месяц никто не вспомнит смысл третьего параметра, вызывающий код передаёт структуру только с нужными ключами, а процедура накладывает её на значения по умолчанию. Для этого пригодится общий модуль: безопасное получение значения, слияние двух структур, полная копия и список ключей строкой.
// Общий модуль РаботаСоСтруктурамиКлиентСервер
// Флажки: «Сервер», «Клиент (управляемое приложение)», «Клиент (обычное приложение)»,
// «Внешнее соединение»; «Вызов сервера» снят.
// Платформа 8.3.6 и новее, режим совместимости конфигурации - не ниже 8.3.6
// (используется СтрСоединить).
#Область ПрограммныйИнтерфейс
// Возвращает значение ключа или значение по умолчанию, если такого ключа нет.
//
// Параметры:
// Структура - Структура, ФиксированнаяСтруктура - где искать.
// Ключ - Строка - имя ключа.
// ЗначениеПоУмолчанию - Произвольный - что вернуть, если ключа нет.
//
// Возвращаемое значение:
// Произвольный - значение ключа или ЗначениеПоУмолчанию.
//
Функция ЗначениеКлюча(Структура, Ключ, ЗначениеПоУмолчанию = Неопределено) Экспорт
НайденноеЗначение = Неопределено;
Если Структура.Свойство(Ключ, НайденноеЗначение) Тогда
Возврат НайденноеЗначение;
КонецЕсли;
Возврат ЗначениеПоУмолчанию;
КонецФункции
// Переносит ключи Источника в Приемник.
//
// Параметры:
// Приемник - Структура - дополняемая структура, изменяется на месте.
// Источник - Структура, ФиксированнаяСтруктура - откуда брать ключи.
// Заменять - Булево - Истина: значения Источника перекрывают совпавшие ключи Приемника;
// Ложь: совпавшие ключи Приемника остаются как были.
//
Процедура Дополнить(Приемник, Источник, Заменять = Истина) Экспорт
Для Каждого Элемент Из Источник Цикл
Если Заменять Или Не Приемник.Свойство(Элемент.Ключ) Тогда
Приемник.Вставить(Элемент.Ключ, Элемент.Значение);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
// Полная копия коллекции: вложенные структуры, соответствия и массивы
// тоже копируются. Фиксированные коллекции в копии становятся обычными.
//
// Параметры:
// Значение - Произвольный - что копировать.
//
// Возвращаемое значение:
// Произвольный - копия коллекции; прочие значения возвращаются как есть.
//
Функция КопияКоллекции(Значение) Экспорт
ТипЗначения = ТипЗнч(Значение);
Если ТипЗначения = Тип("Структура") Или ТипЗначения = Тип("ФиксированнаяСтруктура") Тогда
Результат = Новый Структура;
Для Каждого Элемент Из Значение Цикл
Результат.Вставить(Элемент.Ключ, КопияКоллекции(Элемент.Значение));
КонецЦикла;
Возврат Результат;
ИначеЕсли ТипЗначения = Тип("Соответствие") Или ТипЗначения = Тип("ФиксированноеСоответствие") Тогда
Результат = Новый Соответствие;
Для Каждого Элемент Из Значение Цикл
Результат.Вставить(Элемент.Ключ, КопияКоллекции(Элемент.Значение));
КонецЦикла;
Возврат Результат;
ИначеЕсли ТипЗначения = Тип("Массив") Или ТипЗначения = Тип("ФиксированныйМассив") Тогда
Результат = Новый Массив;
Для Каждого Элемент Из Значение Цикл
Результат.Добавить(КопияКоллекции(Элемент));
КонецЦикла;
Возврат Результат;
КонецЕсли;
// Строки, числа, даты, ссылки неизменяемы - копировать их не нужно
Возврат Значение;
КонецФункции
// Ключи структуры одной строкой через запятую - для логов и отладки.
//
// Параметры:
// Структура - Структура, ФиксированнаяСтруктура - источник ключей.
//
// Возвращаемое значение:
// Строка - например, "Артикул, Цена".
//
Функция КлючиСтрокой(Структура) Экспорт
Ключи = Новый Массив;
Для Каждого Элемент Из Структура Цикл
Ключи.Добавить(Элемент.Ключ);
КонецЦикла;
Возврат СтрСоединить(Ключи, ", ");
КонецФункции
#КонецОбласти
Так модуль используется в серверном коде обработки:
// Модуль объекта обработки выгрузки (сервер)
Функция НовыеНастройкиВыгрузки() Экспорт
Настройки = Новый Структура;
Настройки.Вставить("РазмерПакета", 500);
Настройки.Вставить("ТолькоИзмененные", Истина);
Настройки.Вставить("ВыгружатьЦены", Ложь);
Настройки.Вставить("Комментарий", "");
Возврат Настройки;
КонецФункции
Процедура ВыполнитьВыгрузку(ПараметрыВызова = Неопределено) Экспорт
Настройки = НовыеНастройкиВыгрузки();
Если ПараметрыВызова <> Неопределено Тогда
// Ключ с опечаткой не должен молча игнорироваться
Для Каждого Элемент Из ПараметрыВызова Цикл
Если Не Настройки.Свойство(Элемент.Ключ) Тогда
ВызватьИсключение СтрШаблон("Неизвестный параметр выгрузки: %1", Элемент.Ключ);
КонецЕсли;
КонецЦикла;
РаботаСоСтруктурамиКлиентСервер.Дополнить(Настройки, ПараметрыВызова, Истина);
КонецЕсли;
РазмерПакета = Настройки.РазмерПакета;
Если Настройки.ВыгружатьЦены Тогда
// выгрузка цен пакетами по РазмерПакета строк
КонецЕсли;
КонецПроцедуры
Процедура ВыгрузитьЦеныМалымиПакетами() Экспорт
// Передаём только то, что отличается от умолчаний
ВыполнитьВыгрузку(Новый Структура("РазмерПакета, ВыгружатьЦены", 100, Истина));
КонецПроцедуры
Структура.Свойство(Ключ, НайденноеЗначение) в ЗначениеКлюча() — одна проверка вместо пары «есть ли ключ» и «прочитать». Функция принимает и ФиксированнуюСтруктуру: у неё тоже есть метод Свойство.Если Заменять Или Не Приемник.Свойство(Элемент.Ключ) в Дополнить() — при Заменять = Ложь процедура только достраивает недостающие ключи, существующие не трогает. Так удобно дозаполнять умолчаниями то, что передал вызывающий код.ВыполнитьВыгрузку() ловит опечатки. Без него ключ РазмерПакет без последней буквы молча проигнорировался бы, и выгрузка пошла бы пакетами по 500 строк.КопияКоллекции() определяет вид коллекции через ТипЗнч и рекурсивно пересоздаёт вложенные структуры, соответствия и массивы. Строки, числа, даты и ссылки неизменяемы, их функция возвращает как есть.Модуль с флажками «Сервер», «Клиент (управляемое приложение)», «Клиент (обычное приложение)» и «Внешнее соединение» при снятом «Вызове сервера» доступен из любого контекста: его код компилируется и на клиенте, и на сервере.
СтрСоединить и СтрШаблон требуют платформу 8.3.6 или новее и режим совместимости конфигурации не ниже 8.3.6. Если старую конфигурацию перевели на новую платформу, а режим совместимости оставили 8.3.5 или ниже, модуль не скомпилируется с ошибкой «Процедура или функция с указанным именем не определена (СтрСоединить)». Тогда соберите строку циклом, а СтрШаблон в ВыполнитьВыгрузку() замените сложением строк:
Функция КлючиСтрокой(Структура) Экспорт
Результат = "";
Для Каждого Элемент Из Структура Цикл
Если Не ПустаяСтрока(Результат) Тогда
Результат = Результат + ", ";
КонецЕсли;
Результат = Результат + Элемент.Ключ;
КонецЦикла;
Возврат Результат;
КонецФункции
В конфигурациях на БСП есть готовые аналоги: ОбщегоНазначенияКлиентСервер.ДополнитьСтруктуру() и ОбщегоНазначения.СкопироватьРекурсивно() — имена и параметры сверьте с версией библиотеки в вашей базе.
Ставки = Новый ФиксированнаяСтруктура("НДС, Валюта", 20, "RUB");
// Ставки.Вставить("Скидка", 5); - ошибка: Метод объекта не обнаружен (Вставить)
Копия = Новый Структура(Ставки); // обычная структура, её можно менять
Копия.Вставить("Скидка", 5);
// Поверхностная копия: вложенная структура общая с оригиналом
Исходная = Новый Структура("Код, Адрес", "001", Новый Структура("Город", "Казань"));
Поверхностная = Новый Структура(Новый ФиксированнаяСтруктура(Исходная));
Поверхностная.Адрес.Город = "Самара"; // Исходная.Адрес.Город тоже станет "Самара"
// Полная копия: вложенные коллекции копируются
Полная = РаботаСоСтруктурамиКлиентСервер.КопияКоллекции(Исходная);
Полная.Адрес.Город = "Казань"; // Исходная не меняется
У ФиксированнойСтруктуры нет методов Вставить, Удалить и Очистить, а значения её ключей нельзя переприсвоить. Она нужна там, где данные не должны меняться случайно. Классический случай — функции общих модулей с повторным использованием возвращаемых значений. Если такая функция вернёт обычную структуру, вызывающий код может её изменить, и следующие вызовы получат из кэша уже испорченное значение. Поэтому из таких модулей возвращают фиксированные коллекции.
Отдельного метода копирования у структуры нет. Конструкторы Новый ФиксированнаяСтруктура(Структура) и Новый Структура(ФиксированнаяСтруктура) дают поверхностную копию: вложенные структуры и массивы остаются общими с оригиналом. Для полной копии нужна рекурсия — функция КопияКоллекции() из модуля выше.
| Структура | Соответствие | |
|---|---|---|
| Ключ | строка по правилам имени переменной | любое значение: строка, число, дата, ссылка |
| Регистр букв в ключе | не важен | для строковых ключей важен |
| Обращение | С.Ключ, С["Ключ"] | С["Ключ"], С.Получить("Ключ") |
| Чтение отсутствующего ключа | ошибка | Неопределено |
| Когда брать | набор полей известен при написании кода | ключи берутся из данных |
Если нужна не пара «ключ — значение», а строки с одинаковыми колонками, берите таблицу значений: у массива структур нет ни поиска по колонке, ни сортировки, ни группировки.
Вставить(), необязательный читайте через Свойство(). Частая причина — опечатка в имени ключа в одном из модулей или ключ, который добавляется только при определённом условии.ФиксированнуюСтруктуру. Сделайте изменяемую копию: Новый Структура(Фиксированная).КлючиСтрокой() с циклом.Товар.ИмяПоля ищет ключ «ИмяПоля», а не значение переменной, и падает с той же ошибкой «Поле объекта не обнаружено (ИмяПоля)». Нужны скобки.Знач не спасает: копируется ссылка, а не содержимое. Если функция меняет параметры под себя, пусть работает с копией.Свойство(). Данные.Свойство("Адрес.Город") не проверяет вложенный ключ: точка в имени не означает вложенность. Проверяйте по уровням — сначала Адрес, потом Город внутри него.Методом Свойство("Ключ"): он вернёт Истина или Ложь. Если значение нужно сразу, передайте вторым параметром переменную — проверка и чтение пройдут за одно обращение.
Обойти структуру циклом и собрать Ключ каждого элемента в массив — готового метода у платформы нет. Строкой через запятую ключи отдаст функция КлючиСтрокой() из модуля выше, это удобно для записи в журнал регистрации.
Нет, методов сортировки у неё нет. Если нужен упорядоченный набор, переложите данные в список значений или таблицу значений — у обоих есть сортировка.
Да, если внутри лежат значения, которые существуют и на клиенте: примитивы, ссылки, массивы, другие структуры и соответствия из них. Таблицы значений и объекты справочников и документов на тонкий клиент не передаются — такую структуру соберите и обработайте на сервере, а на клиент верните только нужные поля.
Структуры — основа почти любого кода, но сами по себе задачу бизнеса не решают: они работают внутри отчётов, обработок и обменов. Если нужна готовая обработка или отчёт под ваш учёт, посмотрите услугу разработка отчётов и обработок 1С или разместите задачу на площадке: оценка бесплатная, ответ — в течение рабочего дня.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.