По ссылке или по значению? Ключевое слово Знач и с чем его едят
Разработка - Практика программирования
Заранее извиняюсь за пафосную аннотацию про "расстановку точек", но надо же как-то завлечь вас в статью)) Со своей стороны постараюсь, чтобы аннотация все же оправдывала ваши ожидания.
Вкратце о чем речь
Все это и так знают, но все же в начале напомню, как в 1С могут передаваться параметры метода. Передаваться они могут "по ссылке" и "по значению". В первом случае, мы передаем в метод то же самое значение, что и в точке вызова, а во втором - его копию.
Процедура ПоСсылке(Параметр)
Параметр = 2;
КонецПроцедуры
Параметр = 1;
ПоСсылке(Параметр);
Сообщить(Параметр); // выведет 2
По умолчанию в 1С аргументы передаются по ссылке, и изменение параметра внутри метода будет видно извне метода. Здесь дальнейшее понимание вопроса зависит от того, что именно вы понимаете под словом "изменение параметра". Так вот, имеется в виду повторное присваивание и ничего более. Причем, присваивание может быть неявным, например вызовом метода платформы, который возвращает что-то в выходном параметре.
Но если мы не хотим, чтобы наш параметр передавался по ссылке, то мы можем указать перед параметром ключевое слово Знач.
Процедура ПоЗначению(Знач Параметр)
Параметр = 2;
КонецПроцедуры
Параметр = 1;
ПоЗначению(Параметр);
Сообщить(Параметр); // выведет 1
Все работает, как обещано - изменение (а правильнее сказать "замена") значения параметра не приводит к изменению значения вне метода.
Ну а в чем прикол-то?
Интересные моменты начинаются, когда мы начинаем передавать в качестве параметров не примитивные типы (строки, числа, даты и т.п.), а объекты. Вот тут-то и всплывают такие понятия, как "мелкая" и "глубокая" копия объекта, а также указатели (не в терминах C++, а как абстрактные дескрипторы (handles)).
При передаче объекта (например, ТаблицыЗначений) по ссылке, мы передаем само значение указателя (некий handle), который в памяти платформы "держит" объект. При передаче по значению платформа сделает копию этого указателя.
Иными словами, если, передавая объект по ссылке, в методе мы присвоим параметру значение "Массив", то в точке вызова получим массив. Повторное присваивание значения, переданного по ссылке, видно из места вызова.
Процедура ОбработатьЗначение(Параметр)
Параметр = Новый Массив;
КонецПроцедуры
Таблица = Новый ТаблицаЗначений;
ОбработатьЗначение(Таблица);
Сообщить(ТипЗнч(Таблица)); // выведет Массив
Если же, мы передадим объект по значению, то в точке вызова наша ТаблицаЗначений не пропадет.
Содержимое объекта и его состояние
При передаче по значению копируется не весь объект, а только его указатель. Экземпляр объекта остается одним и тем же. Неважно, как вы передаете объект, по ссылке или по значению - очистка таблицы значений приведет к очистке именно таблицы. Эта очистка будет видна везде, т.к. объект был один-единственный и неважно, как именно он передавался в метод.
Процедура ОбработатьЗначение(Параметр)
Параметр.Очистить();
КонецПроцедуры
Таблица = Новый ТаблицаЗначений;
Таблица.Добавить();
ОбработатьЗначение(Таблица);
Сообщить(Таблица.Количество()); // выведет 0
При передаче объектов в методы платформа оперирует указателями (условными, не прямыми аналогами из C++). Если объект передается по ссылке, то ячейка памяти виртуальной машины 1С, в которой лежит данный объект, может быть перезаписана другим объектом. Если объект передается по значению, то указатель копируется и перезапись объекта не приводит к перезаписи ячейки памяти с исходным объектом.
В то же время любое изменение состояния объекта (очистка, добавление свойств и т.п.) изменяет сам объект, и вообще никак не связано с тем, как и куда объект передавался. Изменилось состояние экземпляра объекта, на него может быть куча "по-ссылок" и "по-значений", но экземпляр всегда один и тот же. Передавая объект в метод, мы не создаем копию всего объекта.
И это верно всегда, за исключением...
Клиент-серверное взаимодействие
В платформе очень прозрачно реализованы серверные вызовы. Мы просто вызываем метод, а под капотом платформа сериализует (превращает в строку) все параметры метода, передает на сервер, а потом возвращает выходные параметры обратно на клиента, где они десериализуются и живут, как будто ни на какой сервер не ездили.
Как известно, не все объекты платформы являются сериализуемыми. Именно отсюда растет ограничение, что не все объекты можно передать в серверный метод с клиента. Если передать несериализуемый объект, то платформа начнет ругаться нехорошими словами.
В стандартах разработки фирмы 1С рекомендуется всегда в параметрах использовать ключевое слово Знач, если мы не собираемся явно возвращать в параметре некое значение. Это хорошо по нескольким причинам:
- Явное объявление намерений программиста. Глядя на сигнатуру метода, можно четко сказать, какие параметры входные, а какие выходные. Такой код легче читать и сопровождать
- Для того, чтобы изменение на сервере параметра "по ссылке" было видно в точке вызова на клиенте, параметры, передаваемые на сервер по ссылке, платформа обязательно будет сама возвращать на клиента, чтобы обеспечить поведение, описанное в начале статьи. Если параметр не нужно возвращать, то будет перерасход трафика. Для оптимизации обмена данными параметры, значения которых нам не нужны на выходе, нужно помечать словом Знач.
Здесь примечателен второй пункт. Для оптимизации трафика платформа не будет возвращать значение параметра на клиент, если параметр помечен словом Знач. Все это замечательно, но приводит к интересному эффекту.
Как я уже говорил, при передаче объекта на сервер происходит сериализация, т.е. выполняется "глубокая" копия объекта. А при наличии слова Знач объект не поедет с сервера обратно на клиента. Складываем эти два факта и получаем следующее:
&НаСервере
Процедура ПоСсылке(Параметр)
Параметр.Очистить();
КонецПроцедуры
&НаСервере
Процедура ПоЗначению(Знач Параметр)
Параметр.Очистить();
КонецПроцедуры
&НаКлиенте
Процедура ПоЗначениюКлиент(Знач Параметр)
Параметр.Очистить();
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьЗнач()
Список1= Новый СписокЗначений;
Список1.Добавить("привет");
Список2 = Список1.Скопировать();
Список3 = Список1.Скопировать();
// объект копируется полностью,
// передается на сервер, потом возвращается.
// очистка списка видна в точке вызова
ПоСсылке(Список1);
// объект копируется полностью,
// передается на сервер. Назад не возвращается.
// Очистка списка НЕ ВИДНА в точке вызова
ПоЗначению(Список2);
// копируется только указатель объекта
// очистка списка видна в точке вызова
ПоЗначениюКлиент(Список3);
Сообщить(Список1.Количество());
Сообщить(Список2.Количество());
Сообщить(Список3.Количество());
КонецПроцедуры
Резюме
Если вкратце, то резюмировать можно следующим образом:
- Передача по ссылке позволяет "затереть" объект совсем другим объектом
- Передача по значению не позволяет "затереть" объект, но изменения внутреннего состояния объекта будут видны, т.к. идет работа с одним и тем же экземпляром объекта
- При серверном вызове работа идет с РАЗНЫМИ экземлярами объекта, т.к. выполнялось глубокое копирование. Ключевое слово Знач запретит копирование серверного экземпляра обратно в клиентский, и изменение внутреннего состояния объекта на сервере не приведет к аналогичному изменению на клиенте.
Специальные предложения
См. также
Полезные процедуры и функции для программиста 140
07.10.2019 8997 HostHost 23
Таблица значений. Нюансы 191
01.10.2019 8541 Yashazz 35
[Шпаргалка] Программное создание элементов формы 283
06.09.2019 9812 rpgshnik 41
Агрегатные функции СКД, о которых мало кто знает 342
05.09.2019 13067 ids79 44
Отслеживание выполнения фонового задания 141
17.08.2019 10505 ids79 16
Функции СКД: ВычислитьВыражение, ВычислитьВыражениеСГруппировкойМассив 253
08.08.2019 14163 ids79 30
СКД - наборы данных и связи между ними, создание собственной иерархии, вложенные отчеты 131
26.07.2019 12738 ids79 6
Обработчики событий при записи объектов. Зачем и что за чем? 202
25.07.2019 12815 4 AlbinaAAA 23
Управление качеством кода 136
22.07.2019 8265 Stepa86 29
СКД - использование расширений языка запросов, секция ХАРАКТЕРИСТИКИ 147
17.07.2019 11224 ids79 27
Регистры сведений. За кулисами 129
09.07.2019 8777 YPermitin 12
"Меньше копипаста!", или как Вася универсальную процедуру писал 183
04.07.2019 7977 SeiOkami 49
Создание отчетов с помощью СКД - основные понятия и элементы 208
25.06.2019 21062 ids79 17
Многопоточное ускорение однопользовательских нагрузок в 1С + Microsoft SQL Server 2017 179
11.06.2019 12722 dmurk 134
Регистры накопления. Структура хранения в базе данных 176
16.05.2019 19044 YPermitin 27
Выполнение внешней обработки в фоновом задании 149
11.05.2019 11315 Eret1k 23
Выгрузка документа по условию 5
25.04.2019 6104 m-rv 2
Как прикрутить ГУИД к регистру сведений 23
16.04.2019 8733 m-rv 16
О расширениях замолвите слово... 193
07.04.2019 17853 ellavs 122
Git-репозитории для 1С-кода (опыт использования при небольших проектах) 202
28.03.2019 13979 ellavs 83
Трюки с внешними источниками данных 166
14.03.2019 14274 YPermitin 52
Возможности типовых шаблонов ограничения доступа на уровне записей (RLS) 166
03.02.2019 17351 ids79 9
Разработка и сценарное тестирование с Vanessa-ADD. Концепция, теория и сквозной пример создания сценария 222
09.01.2019 27597 Vladimir Litvinenko 69
EnterpriseData – часть 2. Процесс выгрузки данных 127
26.12.2018 13815 ids79 27
Новый подход к обмену данными EnterpriseData 207
14.12.2018 23189 ids79 72
Программное заполнение пользовательских параметров и отборов СКД 136
13.11.2018 22188 Unk92 19
Автоматические и управляемые блокировки применительно к типовым конфигурациям 1С 127
10.11.2018 22288 ids79 40
Вспомогательные инструкции в коде 1С 105
15.10.2018 21532 tormozit 100
Произвольный код в фоновом режиме 165
03.09.2018 15759 nikita0832 42
Основные понятия и механизмы оптимизации клиент-серверного взаимодействия в 1C 147
23.08.2018 22917 Rain88 42
Тестер: частые вопросы 156
25.07.2018 21003 grumagargler 24
Повышаем эффективность разработки правил обмена 124
25.06.2018 20248 olegtymko 47
Введение в механизм представлений в ЗУП ред. 3 156
04.06.2018 25625 xrrg 82
Как сделать запрос на изменение данных 75
01.06.2018 22169 m-rv 21
Строим графы средствами 1С (без GraphViz) 43
23.05.2018 17963 slozhenikin_com 19
Распределение расходов пропорционально продажам 9
13.05.2018 12067 Rustig 9
Просмотр временных таблиц запроса в отладчике без изменения кода 129
24.04.2018 26541 [email protected] 19
[ВсеПросто] "Оперативный" информатор из 1С за 5 мин. 198
22.02.2018 21457 DarkAn 25
Минимализмы 3 355
19.02.2018 37137 ildarovich 44
Этюды по программированию. Взаимодействие с Microsoft Word 109
11.12.2017 26565 milkers 23
Метод формирования движений в типовых регистрах нетиповыми регистраторами 31
05.12.2017 21997 itriot11 34
1С: Конвертация данных 3. Инструкции и примеры. EnterpriseData (универсальный формат обмена) 737
19.11.2017 142820 MaxS 251
Заполнение данных по ИНН контрагента с помощью альтернативного сервиса огрн.онлайн 131
01.11.2017 23735 slava_1c 49
Программные перечисления, ч.2: приемы кэширования при разработке 67
30.10.2017 22064 unichkin 18
Разбираемся с настройками компоновки данных 161
29.10.2017 25127 json 9
Работа с Excel 298
23.10.2017 27126 arakelyan 39
Добавление команд печати в конфигурациях на БСП 2.4.3 (в частности, в самописных документах в Бухгалтерии 3.0 после релиза 3.0.52.35) 144
18.09.2017 48883 bugtester 43
Как сделать из &НаКлиентеНаСервереБезКонтекста почти &НаКлиентеНаСервере 127
10.09.2017 35166 tormozit 72