1с обращение к процедуре как к функции
Эта статья продолжает цикл статей «Первые шаги в разработке на 1С». В ней будут рассмотрены следующие вопросы:
- Что такое процедуры и функции и когда их нужно использовать?
- В чем отличие процедуры от функции?
- Что такое параметр процедуры (функции) и как его передать?
- В каком случае передавать параметр по ссылке, а в каком по значению?
- Как быстро посмотреть список процедур текущего модуля?
Применимость
Материал полностью актуален для платформы «1С:Предприятие 8» редакций 8.2. и 8.3.
Процедуры и функции
В отдельные процедуры и функции можно выносить общие алгоритмы. Одинаковый программный код из разных модулей (какой-то общий алгоритм) разумно выносить в процедуру или функцию какого-нибудь модуля и обращаться к ней.
При этом мы избавляемся от дублирования кода, заменив его вызовом процедуры (функции). Если возникает потребность внести изменения в алгоритм, то эти изменения будет достаточно внести в одном месте.
Кроме того, процедуры и функции повышают читаемость программного кода. Гораздо проще просмотреть, что выполняет данный код, особенно, если вызовы процедур имеют осмысленные названия.
В итоге облегчается сопровождение прикладного решения.
Следует отметить, что начинающие разработчики иногда для названия процедуры или функции пытаются использовать зарезервированное слово Выполнить.
Зарезервированные слова использовать для этих целей нельзя, и, естественно, в этом случае система будет сообщать об ошибке.
Функция, в отличии от процедуры, может иметь возвращаемое значение. В теле функции для того, чтобы вернуть значение, нужно использовать оператор Возврат и указать то значение, которое будет возвращаться.
Процедура, в отличии от функции, не может иметь возвращаемое значение. Она просто вызывается и выполняет какие-то действия.
Если функция не будет иметь ключевого слова Возврат, то она вернет несуществующее значение, т.е. значение типа данных Неопределено. Вместе с тем, ключевое слово Возврат можно использовать и в процедуре, но в этом случае возвращаемое значение не указывается, а само ключевое слово будет означать: прекратить выполнение процедуры.
Процедура или функция начинает описываться со слова Процедура (Функция). Далее следует Имя процедуры (функции). После имени обязательно указываются круглые скобки. Внутри скобок могут находиться описываемые параметры.
Данные параметры нужно будет передавать при вызове (при обращении к процедуре). После круглых скобок может стоять слово Экспорт (экспортная функция).
Потом следует тело процедуры (функции), т.е. последовательность из любого количества операторов.
В теле могут находиться вызовы других процедур и функций данного модуля или других модулей, которые доступны из текущего программного модуля. Обязательным является наличие заключительного слова КонецПроцедуры (КонецФункции).
После описания процедуры или функции точку с запятой ставить не нужно. При этом Платформа не считает ошибкой, если точка с запятой стоит после последней процедуры (функции) в модуле.
Параметры, переданные в процедуру (функцию) при ее вызове, могут быть использованы при формировании возвращаемого результата функцией или при выборе используемого алгоритма в процедуре.
При описании процедуры или функции мы можем указать, что для какого-либо параметра по умолчанию должно использоваться некоторое значение. Для этого справа от параметра через знак равенства указывается требуемое значение.
В том случае, если при вызове процедуры (функции) значение параметра будет не задано, то оно примет значение, используемое по умолчанию.
Таким образом, параметры, для которых указано значение по умолчанию, являются необязательными для указания при вызове. В описании процедуры(функции) вначале следуют обязательные параметры, а потом необязательные.
Кроме этого, существует передача параметров по ссылке и по значению. Внутри процедуры (функции) параметр может анализироваться, а также может изменяться. Все данные хранятся в оперативной памяти компьютера.
При передаче по ссылке система сообщает, что нужно обратиться к переменной, которая хранится в данной области памяти. В том случае, если значение параметра изменяется, оно меняется именно в указанной области памяти.
Т.е. при вызове процедуры (функции) мы передавали параметр с одним значением, а после отработки вызываемой процедуры (функции) значение параметра изменилось.
В случае передачи по значению указывается, что параметр нужно передавать по значению.
В этом случае вызывается новая область памяти, отличная от предыдущей, и меняется именно она. Исходное значение параметра не меняется.
По умолчанию все параметры передаются по ссылке. Чтобы передать параметр по значению, в описании процедуры перед параметром нужно поставить ключевое слово Знач.
Следует сказать, что в некоторые процедуры-обработчики передается такой параметр, как Отказ. Значение данного параметра по умолчанию – Ложь.
Если в теле процедуры-обработчика установить данному параметру значение Истина, то процедура не отработает.
Порядок следования процедур и функций в модуле 1С:Предприятие 8 значения не имеет. Из любой процедуры (функции) модуля можно вызывать любую другую процедуру или функцию данного модуля.
Чтобы обратиться к списку процедур текущего модуля в панели конфигуратора можно нажать на кнопку в виде лупы с надписью «PROC» или использовать горячие клавиши (Ctrl+Alt+P).
Откроется диалоговое окно, в котором описаны функции F(x) и процедуры P( ). К ним возможно обращаться.
Список может быть отсортирован в алфавитном порядке (для этого устанавливается галочка «Сортировка»).
При снятой галочке процедуры и функции в списке размещены в соответствии с их следованием в модуле.
Кроме процедур и функций в списке для разных модулей будут доступны разные стандартные обработчики. При выборе обработчика двойным кликом мыши в модуле создается шаблон соответствующей процедуры (обработчика события).
Если в диалоговом окне «Процедуры и функции» выбрать процедуру и нажать на кнопку Перейти, то мы окажемся в начале выбранной процедуры (функции).
Справа от кнопки с надписью «PROC» располагается поле. В этом поле указано имя текущей процедуры (функции).
Первичное знакомство с процедурами и функциями будем считать завершенным. Однако отметим, что платформа содержит множество стандартных процедур и функций, логику которых вам не нужно писать самостоятельно. Достаточно только в случае необходимости вызвать их в нужном месте вашего программного кода. Изучением этих стандартных функций мы и займемся в нашей следующей статье :)
PDF-версия статьи
Если Вы еще не вступили в группу – сделайте это сейчас и в блоке ниже (на этой странице) появятся ссылка на скачивание материалов.
Статья в PDF-формате
Если Вы уже участник группы – нужно просто повторно авторизоваться в ВКонтакте, чтобы скрипт Вас узнал. В случае проблем решение стандартное: очистить кеш браузера или подписаться через другой браузер.
Ковыряя одну конфу от Раруса, обратил внимание, что очень много параметров процедур и функций в общих модулях описаны с использованием ключевого слова Знач. Такое описание делается даже в тех случаях, когда 100% с данные только читаются (т.е. исключено изменение объекта).
Подумалось следующее. А не фича ли это?
Ведь Знач (в случае передачи ссылки) на уровне СУБД по сути одним запросом выберет копию объекта и передаст в процедуру/функцию, где уже можно спокойно с ней работать, без дергания сервера мелкими запросами при обращении к свойствам объекта по ссылке.
Прав ли я или тут закопан какой-то другой смысл?
В-четвёртых, использование ключевого слова Знач при объявлении параметров процедур и функций. Дело в том, что при клиент-серверном взаимодействии это ключевое слово значит совсем не то, что при работе внутри одного компьютера, клиентского или серверного. Когда мы используем Знач при объявлении параметра серверной процедуры и вызываем её с клиента, это означает, что значение этого параметра обратно на клиент не приедет. Если же мы не устанавливаем Знач, а стандартно так и есть, то происходит следующее. Допустим, мы вызываем серверную процедуру и передаём в неё массив. Предположим, что на клиенте мы даже не собираемся потом этим массивом пользоваться. Он просто был параметром и на самом деле нам не нужен больше. Но когда серверный вызов закончится, массив будет упакован в XML или JSON (на веб-клиенте), и уедет обратно на клиент. Понятно, что это совсем неэффективно. Поэтому если вам не нужно возвращаемое значение, переданное через параметр, пишите ключевое слово Знач у таких параметров. Конечно, если параметр Булево, Знач можно сэкономить и не писать. Но по сути это нехорошо.
(0) Я бы не стал конфу от раруса рассматривать, как объект для подражания. Смотрел УАТ, так в шоке был от увиденного.
Значит в клиент-серверном варианте, если передавать через Знач ссылку на, к примеру элемент справочника, то в процедуру/функцию все равно придет ссылка, а не копия объекта элемента справочника?
Первый - сугубо идеологический. Указывая "Знач" вы явно объявляете свое намерение сделать параметр строго входным (обязуетесь не изменять параметр)
Любой человек, который ваш код будет читать, может посмотреть на сигнатуру метода и сказать: "так, эти два параметра входные, а вот этот без "Знач" - выходной, он где-то в коде присваивается и в нем что-то возвращается". То есть, указывая знач, вы облегчаете чтение своего кода и явно объявляете намерения в сигнатуре метода.
Второй аспект - технический. При передаче чего-то на сервер, если параметр без слова "Знач", то платформа считает этот параметр выходным и при возврате на клиента будет обратно передавать его значение. Указывая Знач вы оптимизируете трафик.
а по поводу копии объекта, это вы не понимаете что такое ссылка. Ссылка это просто GUID. Ее можете передавать с сервера на клиент и обратно, никаких копий "объектов" не создается.
СправочникОбъект на сервер передать вообще нельзя, это мутабельное значение.
Когда вы пишете "А = Ссылка.Наименование" происходит запрос в СУБД и в память поднимается ВЕСЬ объект вместе со всеми табличными частями. Передавая ссылку на сервер вы передаете только GUID. Эти два процесса (запрос в базу и передача ссылки) вообще не связаны никак.
(11) А, ну понял. Меня просто СП сбил с толку.
Получается если мы передаем ссылку на элемент справочника, то без Знач передаем ссылку на ссылку, вернее указатель на ссылку. А со Знач само значение ссылки.
(12) %) Я Ничего Не Понял
Если мы передаем со Знач или без Знач ссылку, то мы передаем GUID. Ссылка в базе данных и Ссылка на объект в памяти это как бы разные ссылки, не находите?
Вот здесь будет переход с машины на машину (с клиента на сервер). Параметр передается "по ссылке". Поскольку это две разных машины, то у них никак не может быть общая память. Платформа здесь делает следующее:
1. Передает значение 0 на сервер (по сути делает копию переменной А)
2. На сервере устанавливается некой переменной значение 1
3. При возврате на клиента платформа помнит, что передача должна быть "как бы по ссылке" и присваивает в А значение, установленное на сервере.
Теперь, если поменять код и вместо &НаКлиенте написать &НаСервере, то будет следующее:
1. В метод ПоСсылке будет передан условный адрес переменной А, по этому адресу записано значение
2. В точке вызова будет видно, что А стало равно единице.
Я, собственно, к чему. Не думайте про ссылки, как про указатели. Если происходит переход с одной машины на другую, то в любом случае будет задействована сериализация туда и обратно. Слово Знач указывает на то каким должно быть НАБЛЮДАЕМОЕ поведение в коде. Технически это могут быть более сложные вещи.
(0) Знач не имеет никакого отношения к СУБД
(6) ИМХО там в большинстве случаев параметры передаются по значению, скорее передаче по ссылке является исключением.
Использование знач для ссылок приводит к созданию новой ссылки то есть другого обьекта с типом ссылка
(16) "Использование знач для ссылок приводит к созданию новой ссылки то есть другого обьекта с типом ссылка" - какие-нибудь подтверждения этому тезису есть?
В документации сказано, что агрегаты передаются всегда по ссылке.
(17) "По ссылке" означает, что если вы перезапишете переменную внутри функции, то она изменится и в точке вызова.
Если "По Значению", то в точке вызова останется то же значение.
Если передали "По значению" коллекцию, внутри метода вызвали Очистить(), то в точке вызова она тоже будет очищена. Вы не перезаписали переменную коллекции, а вызвали метод, который изменил внутренности объекта. Т.е. агрегат (коллекция) как бы ни передавался - если вы меняете состояние объекта - оно меняется везде.
Вот правда вы как школьники.
Это же основы программирования.
С Знач копия объекта создается в процедуре и там же умирает.
Без Знач- передается ссылка(и это может быть ссылка на объект с возможностью изменения) . Вот тут возможны варианты когда работать или не будет или не оптимально.
Вот не знаю как там внутре 1С, некоторые другие языки создают копию объекта только в момент изменения. Если вы понимаете о чем я.
Но на самом деле это не имеет значения.
Хотя изредка очень хочется, чтобы про типобезопасность и имьютабилити платформа "думала" сама.
В контексте ветки внимание, вопрос: зачем нужна такая функция:
На ИТС есть же статья "Передача параметров по ссылке и по значению при вызове процедур и функций"? Там всё подробно разжёвано.
(8) Сделайте в отладчике остановку по ошибке и посмотрите чему равен врТабличныйДокумент в момент ошибки.
(5)Хороший скрин, а главное на нужном свойстве курсор, так вот, если "вывод" запрещен, у вас и будет ошибка в методе записать.
(5)"Если право доступа "Вывод" установлено, то вывод разрешен, иначе запрещен." у вас стоит "Авто", значит контроль на уровне прав, т.е. у кого то есть вправо вывода у кого то нет, у тех у кого нет, вылазит ошибка на методе "Записать"
(62)
ТабличныйДокумент (SpreadsheetDocument)
Вывод (Output)
Использование:
Чтение и запись.
Описание:
Тип: ИспользованиеВывода.
Ограничение вывода на печать, сохранения, работы с буфером обмена.
Тонкий клиент, веб-клиент, сервер, толстый клиент, внешнее соединение.
ИспользованиеВывода (UseOutput)
Значения
Авто (Auto) (при авто используется право вывода пользователя).
Запретить (Disable)
Разрешить (Enable)
Содержит варианты использования права доступа Вывод.
ТекстовыйДокумент, свойство Вывод
ТабличныйДокумент, свойство Вывод
ПолеHTMLДокумента, свойство Вывод
ТабличноеПоле, свойство Вывод
ГеографическаяСхема, свойство Вывод
ГрафическаяСхема, свойство Вывод
(12)
Это получение каталога в модуле формы
Если вы про этот кусок, то там ДокументРезультат, а какой у него тип мы не знаем, но я подозреваю что не табличный документ
(19) Закоментируйте функцию получитькатолог, а вот этот кусок раскомменте, только вместо ДокументРезультат.Записать(ВремФайл,ТипФайлаТабличногоДокумента.PDF); напишите врТабличныйДокумент.Записать(ВремФайл,ТипФайлаТабличногоДокумента.PDF);
(19) потому-что отладчик всегда работает как получение результата.
Т.е. в отладчике этот код будет вызван как функция. Что соответственно приводит к ошибке. Нельзя в отладчике это проверять.
(24) Она работает, сохраняет, но не всегда
Раз я запущу допустим, он сохранит 30 платежёк, второй раз в другую папку пытаюсь сохранить, просто вываливает "Не удалось сохранить т.д т.п" и даже печатку не выводит показать.
(24) Может ли это быть как то связано с сервером? То есть при сохранении на сервер отказ идёт?
Потому что у меня при открытии внешней обработки более 2ух раз вываливается "Ошибка файловой операции и путь"
(26) ну тут может быть что угодно вплоть до отсутствия места на диске и прав на папку, надо смотреть в момент ошибки
(24) ошибка связана именно с вычислением выражения в отладчике.
Может что и не работает, но с другой ошибкой.
ТабличныйДокумент (SpreadsheetDocument)
Записать (Write)
Вариант синтаксиса: В файл
Тип: Строка.
Имя файла, в котором сохраняется табличный документ.
(необязательный)
Тип: ТипФайлаТабличногоДокумента.
Формат, в котором будет сохранен табличный документ.
Значение по умолчанию: MXL.
Описание варианта метода:
Запись табличного документа в файл.
Если файловая база - проверьте у пользователя доступность ко всем каталогам на чтение и запись, если серверная - у пользователя 1cv8User доступ на чтение и запись к каталогам.
(35) Посмотрите чему равны ВремФайл, ИмяФайла при нормальном функционировании и при ошибке
ВремФайл = ПолучитьИмяВременногоФайла("pdf");
ИмяФайла = ЭтотОбъект.КаталогВыгрузки + "\" + ТНаим + ".pdf";
врТабличныйДокумент.Записать(ВремФайл,ТипФайлаТабличногоДокумента.PDF);
По синтаксису должно быть
или я что-то в беседе пропустил и про это проговорили ?
Глобальный контекст.ПереместитьФайл (Global context.MoveFile)
Глобальный контекст (Global context)
ПереместитьФайл (MoveFile)
Синтаксис:
Тип: Строка.
Полное имя файла-источника (полное исходное имя файла).
(обязательный)
Тип: Строка.
Полное имя файла-приемника (полное новое имя файла).
Описание:
Выполняет перемещение (переименование) указанного файла.
Тонкий клиент, веб-клиент, мобильный клиент, сервер, толстый клиент, внешнее соединение, мобильное приложение(клиент), мобильное приложение(сервер).
Примечание:
&НаКлиенте
Процедура ЗаполнитьПодразделения (НомерПриложения)
ЭтотОбъект [СтрШаблон ("Подразделения%1", НомерПриложения)]. Очистить ();
СтрПоОрганизации = ЭтотОбъект [СтрШаблон ("Подразделения%1", НомерПриложения)]. Добавить ();
СтрПоОрганизации. НаимЮЛ = "По организации";
СтрПоОрганизации. ИтогоПоПоставкам = ПересчетИтогов6и7(НомерФормы);
//
Для Каждого СтрПодразделения Из Отчет [СтрШаблон ("ТЧПодразделения%1", НомерПриложения)] Цикл
СтрПодразделенияНаФорме = ЭтотОбъект [СтрШаблон ("Подразделения%1", НомерПриложения)]. Добавить ();
ЗаполнитьЗначенияСвойств (СтрПодразделенияНаФорме, СтрПодразделения);
КонецЦикла;
КонецПроцедуры
Ошибка в "СтрПоОрганизации. ИтогоПоПоставкам = ПересчетИтогов6и7(НомерФормы); "
Вот сама процедура:
&НаКлиенте
Процедура ПересчетИтогов6и7(НомерФормы)
ТабличнаяЧасть = ?(НомерФормы = "6", Отчет. ТЧ6_Поставки, Отчет. ТЧ7_Закупки);
ТабличнаяЧастьЭлементы = ?(НомерФормы = "6", Элементы. ТЧ6_Поставки, Элементы. ТЧ7_Закупки);
Для Каждого стрТЧ1 Из ТабличнаяЧасть Цикл
Если ТабличнаяЧастьЭлементы. ДанныеСтроки (стрТЧ1.ПолучитьИдентификатор ()) = Неопределено Тогда
Продолжить;
КонецЕсли;
Сумма = Сумма + ТабличнаяЧастьЭлементы. ДанныеСтроки (стрТЧ1.ПолучитьИдентификатор ()).П000000000021;
КонецЦикла;
Если НомерФормы = "6" Тогда
Элементы. ТЧ6_ПоставкиП000000000021.ТекстПодвала = Формат (Сумма, "ЧЦ=15; ЧДЦ=5");
ИначеЕсли НомерФормы = "7" Тогда
Элементы. ТЧ7_ЗакупкиП000000000021.ТекстПодвала = Формат (Сумма, "ЧЦ=15; ЧДЦ=5");
КонецЕсли;
ТабличнаяЧасть = ?(НомерФормы = "6", Отчет. ТЧ6_Возвраты, Отчет. ТЧ7_Возвраты);
ТабличнаяЧастьЭлементы = ?(НомерФормы = "6", Элементы. ТЧ6_Возвраты, Элементы. ТЧ7_Возвраты);
Для Каждого стрТЧВозвраты Из ТабличнаяЧасть Цикл
Если ТабличнаяЧастьЭлементы. ДанныеСтроки (стрТЧВозвраты. ПолучитьИдентификатор ()) = Неопределено Тогда
Продолжить;
КонецЕсли;
Сумма = Сумма + ТабличнаяЧастьЭлементы. ДанныеСтроки (стрТЧВозвраты. ПолучитьИдентификатор ()).П000000000021;
КонецЦикла;
Если НомерФормы = "6" Тогда
Элементы. ТЧ6_ВозвратыП000000000021.ТекстПодвала = Формат (Сумма, "ЧЦ=15; ЧДЦ=5");
ИначеЕсли НомерФормы = "7" Тогда
Элементы. ТЧ7_ВозвратыП000000000021.ТекстПодвала = Формат (Сумма, "ЧЦ=15; ЧДЦ=5");
КонецЕсли;
Вам надо определиться:
1. у вас ПересчетИтогов6и7() - это функция, тогда первая процедура без изменений, а вот функция все-таки функция
Функция ПересчетИтогов6и7(НомерФормы)
.
Возврат ЧтоХотитеВернуть;
КонецФункции
2. у вас ПересчетИтогов6и7() - это процедура, тогда вторая процедура без изменений, а вот обращаться к ней надо как к процедуре
Процедура ЗаполнитьПодразделения (НомерПриложения)
.
ПересчетИтогов6и7(НомерФормы);
.
КонецПроцедуры
Т. е. если из процедуры хотите получить какое-то значение, то это функция:
ИмяПеременной = ИмяФункции ();
и в самой функции должно быть "Функция" и строка Возврат.
Если вам надо просто пойти в другую процедуру, там пошуршать и вернуться обратно, то никаких равно при ее вызове:
кодкодкод
ВыполнитьПроцедуру ();
кодкодкод
Существует множество статей, которые описывают возможные причины возникновения в 1С ошибки “Поле объекта не обнаружено”. Порой это связывают с обновлением платформы, обновлением типового релиза, или с какими-то другими причинами.
Мы же будем оперировать фактами. В конце статьи прилагается внешняя обработка, в которой воспроизведена данная ошибка.
- Удалили табличную часть, к которой обращаемся в коде?
- Переименовали реквизит, а в коде не исправили?
- Заменили значение со ссылки на неопределено?
Вуаля – платформа выдаст ошибку “Поле объекта не обнаружено”!
Индекс находится за границами массива
- Использование при обходе коллекции количества элементов вместо индекса. Индексы начинаются с нуля, а количество элементов – с единицы. Поэтому следующий код гарантированно приведет к ошибке: Массив[Массив.Количество()]
- Последствия удаления элементов из коллекции, очистки коллекции или замены коллекции на пустую
- Ошибочное увеличение счетчика в цикле “Для”
Обращение к процедуре как к функции
Суть этой ошибки в том, что процедура не может возвращать значение. И если мы в коде используем вызов процедуры справа от знака присваивания, это приведет к ошибке.
Данная ошибка имеет две вариации – если используется стандартная процедура из методов какого-нибудь объекта, то фраза будет звучать “Обращение к процедуре объекта как к функции”. Если же использовать процедуру, объявленную в коде, то текст ошибки будет “Обращение к процедуре как к функции”.
При этом ошибка использования процедуры объекта является ошибкой времени выполнения – т.е. на этапе сохранения и проверки конфигурации платформа эту ошибку не обнаружит.
А вот неправильное использование процедуры синтаксическая проверка (Ctrl + F7) успешно обнаруживает, и не даст сохранить конфигурацию или внешнюю обработку/отчет, пока ошибка не будет устранена.
Рассмотрим два примера:
1. Воспроизведем ошибку “ Обращение к процедуре как к функции” . При этом платформа не даст сохранить изменения, т.к. не проходит синтакс-контроль.
2. Воспроизведем ошибку “ Обращение к процедуре объекта как к функции” . Здесь мы неверно используем метод объекта массива “Добавить”, который является процедурой.
Процедура не может возвращать значение
Переменная не определена
Такой текст ошибки платформа 1С выдает на этапе синтаксического контроля, при сохранении конфигурации, внешнего отчета или обработки.
Причин у этой ошибки может быть несколько.
- Опечатка в имени переменной
- Обращение к переменной, которая нигде в области видимости не объявлена (неявной инициализацией с присвоением значения, явным образом с использованием ключевого слова “Перем”, или передана в качестве параметра)
- Написание на клиенте серверного кода. Например, обращение к менеджеру справочников “Справочники”, и т.п. Клиентская часть приложения “не видит ” серверные объекты языка
- Также ошибка может появиться, если ранее код использовался в режиме толстого клиента, но после был запущен в тонком клиенте.
Внимательно следить за правильностью набранного кода, своевременно объявлять переменные или передавать их в качестве параметров. Писать серверный код только в серверных модулях, а также использовать соответствующие инструкции препроцессора, например “&НаСервере”.
Читайте также: