Оператор «=» во встроенном языке 1С:Предприятия 8.3: типы, видимость, ссылки и клиент-сервер
Содержание
Значение переменной в 1С присваивают оператором =: слева имя, справа выражение, в конце точка с запятой — Сумма = 100;. Объявлять переменную заранее не нужно: она появляется в момент первого присваивания и получает тип того значения, которое ей записали.
Ключевое слово Перем нужно в двух случаях: чтобы объявить переменную модуля (видна во всех процедурах модуля) или чтобы явно завести локальную переменную без значения. Синтаксис присваивания одинаков в 8.2 и 8.3. Различия между платформами касаются не самого оператора, а того, где живёт переменная: на клиенте или на сервере, в форме или в модуле.
Синтаксис присваивания: как записать значение в переменную
Общая форма одна:
ИмяПеременной = Выражение;
Справа может стоять литерал, другая переменная, результат функции, арифметика или новый объект:
Количество = 5;
Цена = 120.50;
Наименование = "Бумага А4";
ДатаДокумента = '20261007';
Проведен = Истина;
Итог = Количество * Цена; // 602.5
Список = Новый Массив;
Контрагент = Справочники.Контрагенты.ПустаяСсылка();
Пусто = Неопределено;
Правила, которые проверяет синтаксический контроль:
- 🔤 Имя начинается с буквы или
_, дальше буквы, цифры,_. Пробелы и дефисы нельзя. - 🔠 Регистр не важен:
Сумма,СУММАисумма— одна и та же переменная. - 🚫 Нельзя называть переменную ключевым словом (
Если,Цикл,Возврат,Новый). - ➕ Составных операторов нет:
Сумма += 10не работает , пишутСумма = Сумма + 10;. - 🔗 Цепочка
А = Б = 0;не присваивает ноль обеим. Платформа прочитает её как «записать вАрезультат сравненияБ = 0», то естьИстинаилиЛожь.
Последний пункт стоит запомнить. Знак = в 1С работает и как присваивание, и как сравнение. Что именно он значит, определяет позиция: в начале оператора это присваивание, внутри выражения — сравнение.
Условное присваивание одной строкой
Вместо блока Если ... Иначе ... КонецЕсли можно использовать встроенную функцию ?():
СтавкаНДС = ?(ПлательщикНДС, 20, 0);
Подпись = ?(ЗначениеЗаполнено(Ответственный), Строка(Ответственный), "<не указан>");
Первый параметр — условие, второй — значение при Истина, третий — при Ложь. Вкладывать ?() друг в друга можно, но после второго уровня код читается хуже обычного Если.
Значения по умолчанию у новых переменных
| Как появилась переменная | Значение до первого присваивания |
|---|---|
Перем Х; в процедуре или модуле | Неопределено |
Параметр со значением по умолчанию Процедура П(Режим = 1) | 1, если параметр не передали |
| Реквизит формы типа «Число» | 0 |
| Реквизит формы типа «Строка» | "" |
| Реквизит формы ссылочного типа | пустая ссылка |
Обращение к имени, которое нигде не объявлено и ни разу не получало значения, даёт ошибку Переменная не определена (ИмяПеременной). Это частая опечатка в длинных именах.
Типы данных: что происходит при присваивании и смешивании
Язык 1С динамически типизирован. Переменная не привязана к типу: сегодня в ней число, через строку — строка.
Значение = 10; // Число
Значение = "десять"; // теперь Строка, ошибки нет
Удобно, но это частый источник ошибок. Если тип важен, проверяйте его явно:
Если ТипЗнч(Значение) = Тип("Число") Тогда
Результат = Значение * 2;
КонецЕсли;
Неявное приведение: тип задаёт левый операнд
Когда в выражении встречаются разные типы, платформа приводит правый операнд к типу левого:
| Выражение | Результат | Почему |
|---|---|---|
"5" + 3 | "53" | левый — строка, число превращено в строку |
3 + "5" | 8 | левый — число, строка превращена в число |
3 + "пять" | ошибка | строку нельзя преобразовать в число |
ТекущаяДата() + 86400 | дата на сутки позже | к дате прибавляются секунды |
'20261010' - '20261007' | 259200 | разность дат — число секунд (3 суток) |
Сравнение на равенство значений разных типов ошибки не даёт: 5 = "5" вернёт Ложь. А вот 5 < "6" уже вызовет ошибку сравнения.
Явное преобразование
Для надёжного кода приводите типы сами:
Число1 = Число("125.40"); // 125.4
Текст = Формат(1250000, "ЧГ=0"); // "1250000" без пробелов-разделителей
Дата1 = Дата("20261007"); // 07.10.2026 0:00:00
Флаг = Булево(1); // Истина
Код = Строка(Контрагент); // представление ссылки
Строка(Число) вставляет неразрывные пробелы между разрядами: Строка(1250000) даёт "1 250 000". Если строка потом идёт в имя файла, в запрос или во внешнюю систему, используйте Формат(Число, "ЧГ=0").
Число("12,5") с запятой вызовет ошибку, разделитель дробной части — точка. Строку из внешнего файла сначала прогоните через СтрЗаменить(Строка, ",", ".").
Где видна переменная: локальные, модульные и экспортные
Видимость определяется тем, где переменная появилась.
Локальная переменная процедуры
Создана внутри процедуры или функции — живёт до её конца. Другая процедура того же модуля её не видит. При следующем вызове процедуры значение не сохраняется.
Процедура ПосчитатьИтог()
Перем Итог; // можно и без Перем, просто Итог = 0;
Итог = 0;
КонецПроцедуры
Объявления Перем внутри процедуры пишут в самом начале, до исполняемых операторов.
Переменная модуля
Объявлена через Перем в начале модуля, до первой процедуры. Видна во всех процедурах этого модуля:
Перем КэшКурсов;
Процедура ПриОткрытии()
КэшКурсов = Новый Соответствие;
КонецПроцедуры
Если внутри процедуры присвоить значение имени, которое уже объявлено в модуле, новая локальная переменная не создаётся: присваивание перезапишет модульную. Локальная появится, только если объявить её в процедуре через Перем с тем же именем. Отсюда правило: модульным переменным давайте заметные имена, например с префиксом модуля.
Экспортные и «глобальные» переменные
Ключевое слово Экспорт после объявления делает переменную доступной извне:
Перем ТекущийРежим Экспорт;
| Где объявлена | Кто её видит |
|---|---|
| Модуль управляемого приложения | любой клиентский код конфигурации, пока открыт сеанс |
| Модуль объекта (справочника, документа) | код, у которого есть этот объект: Объект.ТекущийРежим |
| Модуль формы | форма-владелец и код, получивший ссылку на форму |
| Общий модуль | нигде: объявлять переменные в общих модулях нельзя |
Аналога глобальной переменной на сервере нет. Для значений, общих на весь сеанс и доступных серверу, используют параметры сеанса (ветка «Общие» → «Параметры сеанса» в конфигураторе) и заполняют их в модуле сеанса.
Особенности 8.3: управляемые формы и асинхронный код
Синтаксис = в 8.3 тот же, что в 8.2. Новое — модель управляемых форм, где код делится на клиентский и серверный. От этого зависит, доживёт ли присвоенное значение до следующего вызова.
Переменная формы на клиенте и на сервере
- 🖥️ Переменная модуля формы на клиенте (
&НаКлиенте Перем ...) хранит значение, пока форма открыта. - 🗄️ Переменная модуля формы на сервере (
&НаСервере Перем ...) существует только во время одного серверного вызова. На следующем вызове её значение пропадёт. - 📋 Значение, которое нужно передать между клиентом и сервером формы, кладут в реквизит формы. Реквизиты сериализуются и уходят туда и обратно.
&НаКлиенте
Перем ПоследнийВыбор; // переживёт открытие и закрытие диалогов
&НаСервере
Процедура ЗаполнитьНаСервере()
Объект.Комментарий = "Заполнено " + Формат(ТекущаяДатаСеанса(), "ДФ=dd.MM.yyyy");
КонецПроцедуры
Не все типы можно передать с сервера на клиент. ТаблицаЗначений, Запрос, объекты справочников и документов на клиент не передаются. Таблицу выгружают в реквизит формы или в массив структур, объект — через ДанныеФормыВЗначение / ЗначениеВДанныеФормы.
Новые способы получить значение в 8.3
- 🧩
СтрШаблон()(с платформы 8.3.6) собирает строку без склейки и ручного приведения:Текст = СтрШаблон("Документ %1 от %2", Номер, Формат(Дата, "ДЛФ=D"));. - ⏳ Асинхронные функции (с 8.3.18):
Ответ = Ждать ВопросАсинх("Продолжить?", РежимДиалогаВопрос.ДаНет);. Значение в переменную попадает после ответа пользователя, без отдельной процедуры-обработчика оповещения. Процедура, где стоитЖдать, объявляется сАсинх.
Ссылки и объекты: присваивание не копирует данные
Для простых типов (Число, Строка, Дата, Булево) присваивание копирует значение. Для коллекций и объектов копируется ссылка: обе переменные указывают на одни и те же данные.
Исходный = Новый Массив;
Исходный.Добавить(1);
Копия = Исходный;
Копия.Добавить(2);
// Исходный.Количество() = 2 — массив один и тот же
Чтобы получить независимую копию:
| Тип | Как скопировать |
|---|---|
ТаблицаЗначений | Новая = Таблица.Скопировать(); |
Массив | цикл с Добавить() в новый массив |
Структура | Новая = Новый Структура; ЗаполнитьЗначенияСвойств(Новая, Старая); — подходит, если ключи заданы заранее |
| вложенные коллекции | рекурсивная функция; в конфигурациях на БСП — ОбщегоНазначения.СкопироватьРекурсивно() |
Ссылка на элемент базы и объект
СправочникСсылка и ДокументСсылка — указатель на запись в базе, а не сама запись. Присвоить ей реквизит нельзя: Контрагент.Наименование = "ООО Ромашка"; даст ошибку, поле объекта только для чтения. Менять данные нужно через объект:
КонтрагентОбъект = Контрагент.ПолучитьОбъект();
КонтрагентОбъект.Наименование = "ООО «Ромашка»";
КонтрагентОбъект.Записать();
Запись объекта в рабочей базе срабатывает сразу, с проверками и подписками на события. Отлаживайте такой код на копии.
Каждое обращение через точку к реквизиту ссылки (Документ.Контрагент.ИНН) читает данные из базы. В цикле это лишние запросы. Значение, нужное несколько раз, получите один раз в переменную или выберите запросом.
Параметры процедур: по ссылке и Знач
По умолчанию параметр передаётся по ссылке. Присваивание параметру внутри процедуры меняет переменную в вызывающем коде:
Процедура Удвоить(Число)
Число = Число * 2;
КонецПроцедуры
А = 5;
Удвоить(А); // А = 10
С Знач процедура получает копию, и вызывающая переменная не меняется: Процедура Удвоить(Знач Число). Для коллекций Знач копирует только ссылку. Новое значение переменной снаружи не появится, но Добавить() в переданный массив будет виден.
В серверном вызове из клиента по-ссылочные параметры после вызова передаются обратно на клиент. Если возвращать нечего, Знач сокращает объём передаваемых данных.
Частые ошибки при присваивании и как их избежать
Практики, которые избавляют от половины этих сюрпризов:
- Одна переменная — один тип. Не используйте
Результатто как число, то как строку. - Счётчики и суммы инициализируйте до цикла:
Итог = 0;. - Проверку на пустоту делайте через
ЗначениеЗаполнено(), а не сравнением с""или0: функция работает и для ссылок, и для дат. - Не храните в клиентской переменной модуля приложения то, что может измениться в базе: значение устареет до конца сеанса.
- Включите проверку модулей в конфигураторе (
Конфигурация → Проверка конфигурации): она находит обращения к необъявленным переменным раньше пользователя.
Частые вопросы
Нужно ли объявлять переменную в 1С перед присваиванием?
Перем обязателен только для переменных модуля и экспортных переменных.Можно ли присвоить значение нескольким переменным сразу?
А = Б = 0 запишет в А результат сравнения. Пишите отдельные операторы: А = 0; Б = 0;.Как очистить переменную?
Неопределено. Для коллекции можно вызвать Очистить(), но тогда очистится и всё, что ссылается на ту же коллекцию.Почему `Строка(1000)` дала «1 000»?
Формат(1000, "ЧГ=0").