1с знач в параметрах процедуры
Передача параметров по ссылке и по значению при вызове процедур и функций
Внимание! Материал данной статьи устарел. Рекомендуется использовать документацию к платформе «1С:Предприятие 8».
Встроенный язык 1С:Предприятия поддерживает два способа передачи параметров в процедуры и функции: передача параметров по ссылке и передача параметров по значению.
Передача параметров по ссылке
По умолчанию, во встроенном языке 1С:Предприятия 8 передача параметров в процедуры и функции осуществляется по ссылке. Это означает, что изменение формального параметра внутри процедуры или функции будет отражаться на значении фактического параметра, переданного при вызове процедуры или функции.
Передача параметров по значению
Особенности передачи переменных различных типов данных по значению
Передача переменных различных типов данных по значению имеет свои особенности. Они заключаются в том, что при работе с методами и свойствами контекста формальных параметров может изменяться состояние фактического параметра, передаваемого при вызове процедуры или функции.
Рассмотрим в качестве примера ситуацию, когда параметром процедуры, передаваемым по значению, является таблица значений. Внутри вызываемой процедуры СвернутьТаблицу() таблица значений, переданная в качестве параметра при вызове процедуры, сворачивается:
Схематично изобразить происходящее при вызове процедуры СвернутьТаблицу(Тз) можно следующим образом:
Разница для всех типов при передаче параметра процедуры или функции по ссылке или по значению проявляется в присвоении фактическому параметру процедуры или функции нового значения. Вызов свойств и методов контекста фактического параметра, если таковые имеются, влияет на формальный параметр независимо от того, передается ли он по ссылке или по значению.
Параметры процедур и функций
Область применения: управляемое приложение, мобильное приложение, обычное приложение.
1. При объявлении формальных параметров процедур и функций (далее по тексту: функций) необходимо придерживаться общих правил образования имен переменных. В частности, имена параметров следует образовывать от терминов предметной области таким образом, чтобы из имени параметра было понятно его назначение.
2. Не следует использовать вместо параметров функций другие средства конфигурирования (переменные модулей, реквизиты формы и т.п.)
3. Параметры в функции должны идти в логической последовательности. Рекомендуется располагать параметры по принципу от общего к частному.
Например, неправильно:
правильно сначала расположить основные параметры ДокументОбъект и Форма :
4. Необязательные параметры (параметры со значениями по умолчанию) должны располагаться после обязательных параметров (без значений по умолчанию).
Например:
5. Не рекомендуется объявлять в функциях много параметров (нужно ориентироваться на количество не более семи параметров), при этом не должно быть много параметров со значениями по умолчанию (нужно ориентироваться на количество не более трех таких параметров). В противном случае, читаемость вызывающего кода сильно снижается. Например, можно легко ошибиться в количестве запятых при передаче необязательных параметров.
При необходимости передавать в функцию большое число параметров рекомендуется:
Правильно пересмотреть логику работы функций, оставив в ней только один ключевой параметр ИмяПоля :
Другой пример. Неправильно:
Правильно сгруппировать параметры, описывающие значения реквизитов номенклатуры, в структуру ЗначенияРеквизитов :
6. При вызове функций необходимо избегать громоздких конструкций, которые приводят к снижению читаемости кода, увеличивают вероятность ошибок и затрудняют отладку.
В частности:
6.1. Не рекомендуется при передаче параметров в одну функцию применять вложенные вызовы других функций.
Неправильно:
Правильно разбивать такие вызовы на отдельные операторы с помощью вспомогательных локальных переменных:
В то же время, если код с вложенными вызовами получается компактным (не требует переноса выражений) и легко читаемым, то вложенные вызовы допустимы.
Например:
Например, для вызова процедуры
Процедура ПоменятьЦветПоляФормы(Форма, ИмяПоля, Цвет)
Использование Знач в процедурах и функциях
Ковыряя одну конфу от Раруса, обратил внимание, что очень много параметров процедур и функций в общих модулях описаны с использованием ключевого слова Знач. Такое описание делается даже в тех случаях, когда 100% с данные только читаются (т.е. исключено изменение объекта).
Подумалось следующее. А не фича ли это?
Ведь Знач (в случае передачи ссылки) на уровне СУБД по сути одним запросом выберет копию объекта и передаст в процедуру/функцию, где уже можно спокойно с ней работать, без дергания сервера мелкими запросами при обращении к свойствам объекта по ссылке.
Прав ли я или тут закопан какой-то другой смысл?
В-четвёртых, использование ключевого слова Знач при объявлении параметров процедур и функций. Дело в том, что при клиент-серверном взаимодействии это ключевое слово значит совсем не то, что при работе внутри одного компьютера, клиентского или серверного. Когда мы используем Знач при объявлении параметра серверной процедуры и вызываем её с клиента, это означает, что значение этого параметра обратно на клиент не приедет. Если же мы не устанавливаем Знач, а стандартно так и есть, то происходит следующее. Допустим, мы вызываем серверную процедуру и передаём в неё массив. Предположим, что на клиенте мы даже не собираемся потом этим массивом пользоваться. Он просто был параметром и на самом деле нам не нужен больше. Но когда серверный вызов закончится, массив будет упакован в XML или JSON (на веб-клиенте), и уедет обратно на клиент. Понятно, что это совсем неэффективно. Поэтому если вам не нужно возвращаемое значение, переданное через параметр, пишите ключевое слово Знач у таких параметров. Конечно, если параметр Булево, Знач можно сэкономить и не писать. Но по сути это нехорошо.
а по поводу копии объекта, это вы не понимаете что такое ссылка. Ссылка это просто GUID. Ее можете передавать с сервера на клиент и обратно, никаких копий «объектов» не создается.
СправочникОбъект на сервер передать вообще нельзя, это мутабельное значение.
Когда вы пишете «А = Ссылка.Наименование» происходит запрос в СУБД и в память поднимается ВЕСЬ объект вместе со всеми табличными частями. Передавая ссылку на сервер вы передаете только GUID. Эти два процесса (запрос в базу и передача ссылки) вообще не связаны никак.
Если мы передаем со Знач или без Знач ссылку, то мы передаем GUID. Ссылка в базе данных и Ссылка на объект в памяти это как бы разные ссылки, не находите?
Вот здесь будет переход с машины на машину (с клиента на сервер). Параметр передается «по ссылке». Поскольку это две разных машины, то у них никак не может быть общая память. Платформа здесь делает следующее:
1. Передает значение 0 на сервер (по сути делает копию переменной А)
2. На сервере устанавливается некой переменной значение 1
3. При возврате на клиента платформа помнит, что передача должна быть «как бы по ссылке» и присваивает в А значение, установленное на сервере.
Теперь, если поменять код и вместо &НаКлиенте написать &НаСервере, то будет следующее:
1. В метод ПоСсылке будет передан условный адрес переменной А, по этому адресу записано значение
2. В точке вызова будет видно, что А стало равно единице.
Я, собственно, к чему. Не думайте про ссылки, как про указатели. Если происходит переход с одной машины на другую, то в любом случае будет задействована сериализация туда и обратно. Слово Знач указывает на то каким должно быть НАБЛЮДАЕМОЕ поведение в коде. Технически это могут быть более сложные вещи.
(0) Знач не имеет никакого отношения к СУБД
(6) ИМХО там в большинстве случаев параметры передаются по значению, скорее передаче по ссылке является исключением.
(17) «По ссылке» означает, что если вы перезапишете переменную внутри функции, то она изменится и в точке вызова.
Если «По Значению», то в точке вызова останется то же значение.
В контексте ветки внимание, вопрос: зачем нужна такая функция:
Параметры процедур и функций в 1С
Передача параметров в процедуры и функции
С помощью параметров можно передавать в процедуру или функцию входные данные. Например:
Функция СуммаЧисел принимает 2 параметра и возвращает сумму этих параметров. При вызове функции параметры передаются по позиции. Слагаемое1 = 2, Слагаемое2 = 3, что соответствует позиции параметров при вызове функции.
Значения, которые передаются в функцию (в данном примере числа 2 и 3) называются аргументами функции. Часто используют такие понятия, как формальные и фактические параметры. Формальные параметры — это параметры процедуры или функции (в данном примере Слагаемое1 и Слагаемое2). Фактические параметры — это значения, которые передаются в процедуру или функцию (в данном примере это числа 2 и 3). То есть фактические параметры и аргументы это одно и то же.
В качестве параметров можно передавать литералы примитивных типов, переменные, сложные выражения:
Значения параметров по умолчанию
Для параметра можно указать значение по умолчанию. Если при вызове функции, параметр не был указан, то берется значение по умолчанию.
Пропущенные и опущенные параметры
Пропущенный параметр — когда при вызове процедуры или функции не указывается его значение и нет значения по умолчанию. В этом случае параметр будет равен Неопределено.
Опущенный параметр — когда явно не указано значение параметра, но для него установлено значение по умолчанию. В этом случае можно не указывать запятую до параметра, если он последний в списке параметров.
Передача параметров по ссылке и по значению
По умолчанию параметры передаются в процедуру или функцию по ссылке. Это значит, что изменение формального параметра в процедуре или функции повлечет за собой изменение фактического параметра.
Чтобы передать параметр по значению в описании процедуры или функции до имени параметра нужно добавить ключевое слово Знач. В этом случае фактический параметр будет скопирован. Изменение формального параметра в процедуре или функции не повлечет за собой изменение фактического параметра.
Если по значению передать объект, например массив, то в процедуре или функции его можно будет очистить. При этом изменить само значение параметра нельзя.
Так происходит, потому что и переменная МассивЗначений и формальный параметр ссылаются на один массив. Но при изменении формального параметра изменится только его значение. Переменная МассивЗначений по прежнему будет ссылаться на массив.
Если две переменные ссылаются на один массив и обе переменные передать в процедуру по ссылке и изменить там, то они по прежнему будут ссылаться на один и тот же массив.
Если при вызове процедуры или функции выполняется вызов сервера, то всегда будут создаваться копии параметров. При возврате на клиента также будут создаваться копии параметров с сервера. Потому что клиент и сервер могут быть разными компьютерами, и у каждого из них своя оперативная память. Если указано ключевое слово Знач, то при возврате управления с сервера на клиента копии параметров не будут передаваться.
Если через параметры передать на сервер структуру с массивами, то будет создана копия как структуры, так и массивов.
Сериализация параметров
Сериализация ‑ это процесс преобразования объекта в поток байтов для сохранения или передачи в память, в базу данных или в файл. Эта операция предназначена для того, чтобы сохранить состояние объекта для последующего воссоздания при необходимости. Обратный процесс называется десериализацией.
Платформа для внутренних нужд всегда использует XDTO-сериализацию в формат XML.
Этапы сериализации параметров при серверном вызове:
По ссылке или по значению? Ключевое слово Знач и с чем его едят
В принципе, любой программист 1С знает, зачем нужно ключевое слово «Знач», позволяющее передавать параметры в метод «по значению». Однако часто оказывается, что все не так просто и термины «по значению» и «по ссылке» вызывают путаницу. В данной заметке хотел бы расставить точки в этом вопросе.
Вкратце о чем речь
| Процедура ПоСсылке(Параметр) Параметр = 2; КонецПроцедуры Параметр = 1; ПоСсылке(Параметр); Сообщить(Параметр); // выведет 2 |
Но если мы не хотим, чтобы наш параметр передавался по ссылке, то мы можем указать перед параметром ключевое слово Знач.
| Процедура ПоЗначению(Знач Параметр) Параметр = 2; КонецПроцедуры Параметр = 1; ПоЗначению(Параметр); Сообщить(Параметр); // выведет 1 |
Ну а в чем прикол-то?
При передаче объекта (например, ТаблицыЗначений) по ссылке, мы передаем само значение указателя (некий handle), который в памяти платформы «держит» объект. При передаче по значению платформа сделает копию этого указателя.
Иными словами, если, передавая объект по ссылке, в методе мы присвоим параметру значение «Массив», то в точке вызова получим массив. Повторное присваивание значения, переданного по ссылке, видно из места вызова.
| Процедура ОбработатьЗначение(Параметр) Параметр = Новый Массив; КонецПроцедуры Таблица = Новый ТаблицаЗначений; ОбработатьЗначение(Таблица); Сообщить(ТипЗнч(Таблица)); // выведет Массив |
Содержимое объекта и его состояние
| Процедура ОбработатьЗначение(Параметр) Параметр.Очистить(); КонецПроцедуры Таблица = Новый ТаблицаЗначений; Таблица.Добавить(); ОбработатьЗначение(Таблица); Сообщить(Таблица.Количество()); // выведет 0 |
В то же время любое изменение состояния объекта (очистка, добавление свойств и т.п.) изменяет сам объект, и вообще никак не связано с тем, как и куда объект передавался. Изменилось состояние экземпляра объекта, на него может быть куча «по-ссылок» и «по-значений», но экземпляр всегда один и тот же. Передавая объект в метод, мы не создаем копию всего объекта.
И это верно всегда, за исключением.
Клиент-серверное взаимодействие
Как известно, не все объекты платформы являются сериализуемыми. Именно отсюда растет ограничение, что не все объекты можно передать в серверный метод с клиента. Если передать несериализуемый объект, то платформа начнет ругаться нехорошими словами.
В стандартах разработки фирмы 1С рекомендуется всегда в параметрах использовать ключевое слово Знач, если мы не собираемся явно возвращать в параметре некое значение. Это хорошо по нескольким причинам:
Как я уже говорил, при передаче объекта на сервер происходит сериализация, т.е. выполняется «глубокая» копия объекта. А при наличии слова Знач объект не поедет с сервера обратно на клиента. Складываем эти два факта и получаем следующее:
| &НаСервере Процедура ПоСсылке(Параметр) Параметр.Очистить(); КонецПроцедуры &НаСервере Процедура ПоЗначению(Знач Параметр) Параметр.Очистить(); КонецПроцедуры &НаКлиенте Процедура ПоЗначениюКлиент(Знач Параметр) Параметр.Очистить(); КонецПроцедуры &НаКлиенте Процедура ПроверитьЗнач() Список1= Новый СписокЗначений; Список1.Добавить(«привет»); Список2 = Список1.Скопировать(); Список3 = Список1.Скопировать(); // объект копируется полностью, // передается на сервер, потом возвращается. // очистка списка видна в точке вызова ПоСсылке(Список1); // объект копируется полностью, // передается на сервер. Назад не возвращается. // Очистка списка НЕ ВИДНА в точке вызова ПоЗначению(Список2); // копируется только указатель объекта // очистка списка видна в точке вызова ПоЗначениюКлиент(Список3); Сообщить(Список1.Количество()); Сообщить(Список2.Количество()); Сообщить(Список3.Количество()); КонецПроцедуры |

