Оператор «=» во встроенном языке 1С:Предприятия 8.3: типы, видимость, ссылки и клиент-сервер

· 9 мин

Содержание

Значение переменной в 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

С Знач процедура получает копию, и вызывающая переменная не меняется: Процедура Удвоить(Знач Число). Для коллекций Знач копирует только ссылку. Новое значение переменной снаружи не появится, но Добавить() в переданный массив будет виден.

В серверном вызове из клиента по-ссылочные параметры после вызова передаются обратно на клиент. Если возвращать нечего, Знач сокращает объём передаваемых данных.

Частые ошибки при присваивании и как их избежать

Диагностика: выберите симптом

Практики, которые избавляют от половины этих сюрпризов:

  1. Одна переменная — один тип. Не используйте Результат то как число, то как строку.
  2. Счётчики и суммы инициализируйте до цикла: Итог = 0;.
  3. Проверку на пустоту делайте через ЗначениеЗаполнено(), а не сравнением с "" или 0: функция работает и для ссылок, и для дат.
  4. Не храните в клиентской переменной модуля приложения то, что может измениться в базе: значение устареет до конца сеанса.
  5. Включите проверку модулей в конфигураторе (Конфигурация → Проверка конфигурации): она находит обращения к необъявленным переменным раньше пользователя.

Частые вопросы

Нужно ли объявлять переменную в 1С перед присваиванием?
Нет. Локальная переменная создаётся первым присваиванием. Перем обязателен только для переменных модуля и экспортных переменных.
Можно ли присвоить значение нескольким переменным сразу?
Нет. А = Б = 0 запишет в А результат сравнения. Пишите отдельные операторы: А = 0; Б = 0;.
Как очистить переменную?
Присвойте Неопределено. Для коллекции можно вызвать Очистить(), но тогда очистится и всё, что ссылается на ту же коллекцию.
Почему `Строка(1000)` дала «1 000»?
Число форматируется по региональным настройкам с разделителем групп. Без разделителя — Формат(1000, "ЧГ=0").
Чем `Перем` в модуле объекта отличается от реквизита объекта?
Переменная модуля живёт только в памяти, пока существует экземпляр объекта, и в базу не записывается. Реквизит хранится в базе.