ВСТРОЕННЫЕ ФУНКЦИИ ПРЕОБРАЗОВАНИЯ ТИПОВ ДАННЫХ
Примеры:
длина = СірДпина("ААББСС"); флаг = ПустаяСтрока(" ААББСС"); новаяСтрока = СокрЛП(" ААББСС "); подстрока = Лев(" ААББСС", 2); подстрока = Прав("ААББСС", 2); подстрока = Сред("ААББСС", 3); подстрока = Сред("ААББСС", 3,2); позиция = Найти("ААББСС", "БС"); позиция = Найти("ААББСС", "БС1"); новаяСтрока = СтрЗаменить("ААББАА", кол = СтрЧислоВхождений("ААББАА",
текст = "Это длинная символьная константа,
// Вернет 6 // Вернет О // "ААББСС"
// Вернет "АА"
// Вернет "СС"
// Вернет "ББСС // Вернет "ББ"
// Вернет 4 // Вернет О "АА", "ДДЦ") "АА");
// Вернет "ДДЦББДДЦ" // Вернет 2
Общие I Текст | Интерфейс Журнаіы |
Конец интервала f~ Текшая дата Конец месяца <• Конец квартала Конец года |
 |
Начало интервала Текущая дата '• Начало иес<»іа Начало квартала Т~ Начало года Г |1010 2001 [^J
Рис. 2.3. Задание начала и конца стандартного интервала на закладке Журналы
 |
Рис. 2.4. Диалог задания дат начала и конца периода |
Примеры: |
рДата = РабочаяДата(); |
// 10.10.01 |
тДата = ТекущаяДата(); |
// 10.10.01 |
новая Дата = ДобавитьМесяц(рДата, -2); |
// 10.08.01 |
нМесяца = НачМесяца(рДата); |
//01.10.01 |
кМесяца = КонМесяца(рДата); |
//31.10.01 |
нКвартала = НачКвартала(рДата); |
//01.10.01 |
кКвартала = КонКвартала(рДата); |
//31.12.01 |
нГода = НачГода(рДата); |
//01.01.01 |
кГода = КонГода(рДата); |
//31.12.01 |
нНедели = НачНедели(рДата); |
//08.10.01 |
кНедели = КонНедели(рДата); |
//14.10.01 |
год = ДатаГод(рДата); |
//2001 |
месяц = ДатаМесяц(рДата); |
//10 |
дч = ДатаЧисло(рДата); |
//10 |
неделя = НомерНеделиГода(рДата); |
//41 |
деньГода = НомерДняГода(рДата); |
//283 |
деньНедели = НомерДняНедели(рДата); |
// 3 |
период = ПериодСтр(нКвартала, кКвартала); |
//4 Квартал 2001 г. |
// Новая установка начала стандартного интервала НачалоСтандартногоИнтервалаС'Месяц"); нИнтервала = НачалоСтандартногоИнтервала( ); |
// Месяц |
|
// Новая установка конца стандартного интервала
КонецСтандартногоИнтервала("Квартал"); // Квартал
кИнтервала = КонецСтандартногоИнгервала(); // 4 Квартал 2001 г.
время = ТекущееВремя(); // 19:53:12
// Подготовка к вызову диалога (рис. 2.4) задания дат начала и конца периода
// Устанавливаем значения дат, отображаемых в диалоге
нПер = '01.04.01'; кПер = '30.06.01';
флаг = ВвестиПериод(нПер, кПер, "Введите период");
Замечание. При работе с датами на всем временном интервале, начиная от рождества Христова, используется григорианский календарь, который берет отсчет от 4 октября 1582 г. по юлианскому календарю. Причем этот день юлианского календаря стах 15 октября 1582 г. в григорианском.
Функцию ТекущееВремя часто употребляют для замера времени вычисление (правда, достаточно продолжительных, поскольку функция не возвращает миллисекунды), например так:
Замеряет время вычислений нСек - время начало вычислений кСек - время конца вычислений
// Фиксируем время начала вычислений
Некоторые вычисления // А это время конца вычислений
перем времяВычислений; перем ин, с;
ТекущееВремя(нЧас, нМин, нСек);
// Некоторые вычисления с = 0;
для ин = 1 по 500000 цикл
с = с + (ин * 2) / ин; //
конецЦикла;
ТекущееВремя(кЧас, кМин, кСек);
// Время вычислений в секундах времяВычислений = (кЧас - нЧас) * 3600 + (кМин - нМин) * 60 + (кСек - нСек); Сообщшъ("Длительность процесса равна " + времяВычислений + " сек."); конецПроцедуры // Выполнить
2.8.4. ВСТРОЕННЫЕ ФУНКЦИИ ПРЕОБРАЗОВАНИЯ ТИПОВ ДАННЫХ
Как мы видели, в выражениях с операндами разных типов данных преобразования типов выполняются автоматически в соответствии с описанными в разд. 2.5 правилами. При этом тип выражения определяется типом его первого операнда. Используя такое свойстве выражений 1С, можно решать вопросы преобразования типов данных, такие, как преобразования "число - строка", "дата - число" и обратные. Покажем это на примерах.
Пример 1. Преобразования "число - строка" и "строка - число".
перем а, б, стр; а =123.45;
// Преобразование "число - строка". Переменная стр имеет символьный тип, поскольку // первый операнд выражения "" + а - это строка
стр = "" + а; // В результате имеем стр = "123.45"
стр = стр + "67"; // Имеем: стр = "123.4567"
// Имеем: стр = "25.10.02"
// Напечатает Строка
Некоторые преобразования типов данных можно выполнять, применяя приведенные в табл. 2.10 встроенные преобразовывающие функции.
Таблица 2.10
Функции преобразования типов данных |
Функция |
Что делает |
Вариант 1:
дат = Дата(параметр); Вариант 2:
дат = Дата(год, месяц, число); |
В первом варианте функция преобразовывает значение выражения параметр в значение типа Дата. Выражение может быть числовым, символьным или типа Дата. В первом случае значение выражения трактуется как число дней от Рождества Христова и преобразовывается в соответствующую дату, во втором случае строка преобразовывается в дату, в третьем преобразований не выполняется.
Во втором варианте функция преобразовывает дату, заданную числовыми выражениями год, месяц, число, в значение типа Дата. Причем для задания значения параметра год используются все цифры, а не две последние |
|
Функция |
Что делает |
стр = Строка(параметр); |
Преобразовывает значение выражения параметр в строку. Выражение может быть датой или иметь числовой или символьный тип. В последнем случае преобразований не выполняется |
чис = Чиспо(параметр); |
Преобразовывает значение выражения параметр в число. Выражение может быть датой или иметь символьный или числовой тип. В последнем случае преобразований не выполняется |
|
Примеры (используем при выводе две цифры для представления года даты): |
2.8.5. ФОРМАТИРОВАНИЕ ДАННЫХ
Представление данных при их выводе на различные носители можно изменять, применяя встроенную функцию Формат, имеющую следующий синтаксис:
представлениеЗначения = Формат(значение, форматнаяСтрока);
Функция Формат, получив значение, преобразовывает его в соответствии с правилами, заданными символьным параметром форматнаяСтрока, и возвращает результат в виде строки с отформатированными данными.
Пример. Выводится число -123.45 на поле длиной в 9 символов. В четырех последних символах поля отображаются знаки числа, стоящие после десятичной точки.
Сообщить(Формат(-123.45, "49.4")); // Напечатает -123.4500
Форматная строка может начинаться с символов Ч, С или Д, если форматируются соответственно числовые, символьные данные или даты. Если тип данных не соответствует, употребленному символу, то до форматирования будет выполнено соответствующее преобразование типов, например
Сообщить(Формат("21-я строка", "45.2")); // Напечатает 21.00
2.8.5.1. ФОРМАТИРОВАНИЕ ЧИСЛОВЫХ ДАННЫХ
Параметр форматнаяСтрока при форматировании числовых данных в общем случае имеет следующий вид:
"Ч[3][0][Д][.Т][Р1][Р2][>С]"
Появляющиеся в форматной строке обозначения имеют следующий смысл:
• 3 - заполнитель ведущих пробелов, присутствующих в строке-результате функции Формат. Если на месте заполнителя указать (0), то ведущие пробелы заменяются на нули;
• 0 - флаг вывода пустого поля, когда форматируемое значение равно нулю;
• Д - длина результирующей строки в символах;
• Т - число знаков после десятичной точки (точность);
• Р1 - символ, отделяющий целую часть числа от нецелой. По умолчанию в качестве разделителя Р1 используется точка;
• Р2 - символ, разделяющий триады. (Триада - это тройка последовательных чисел в целой части числа. Например, число 1234567 при форматировании с разделением на триады, когда на месте Р2 стоит символ ', примет вид 1'234'567.) По умолчанию триады не разделяются;
• С - размер правого сдвига форматируемого значения. В результате сдвига удаляются С правых символов целой части форматируемого числа.
Примеры:
Сообщить(Формат( 1234567.89, "Ч(0)20.4")); // Напечатает 000000001234567.8900
Сообщить(Формат( 1234567.89, "Ч14.4,_")); // Напечатает 1_234_567,8900
Сообщить(Формат( 123456000, "Ч(0)14>3")); // Напечатает 00000000123456
Если длина результирующей строки недостаточна для представления значения, то на месте результата напечатаются девятки и заданные разделители, например
Сообщить(Формат(1234567.89, "Ч8.2,_")); // Напечатает 9_999,99 .
Функция Формат выполнит преобразование "число - строка" без форматирования, если форматная строка не содержит компонентов Д и/или .Т или не имеет вид "ЧП[Д][С]", например
пред = Формат(21, "ЧМ"); // Вернет 21
2.8.5.2. ВЫВОД ДЕНЕЖНЫХ ВЕЛИЧИН И ЦЕЛЫХ ЧИСЕЛ ПРОПИСЬЮ
Форматируемое значение выводится
• прописью как целое число, если форматная строка имеет вид "ЧП";
• прописью в виде денежной суммы без копеек, если форматная строка имеет вид "ЧПД";
• прописью в виде денежной суммы с копейками, если форматная строка имеет вид "ЧПДС";
Примеры:
Сообщить(Формат(59421.67, "Ч П"));
Сообщить(Формат(5 9421.67, "ЧЦД"));
Сообщить(Формат(59421.67, "ЧПДС"));
Пятьдесят девять тысяч четыреста двадцать два Пятьдесят девять тысяч четыреста двадцать два рубля Пятьдесят девять тысяч четыреста двадцать один рубль 67 копеек
По умолчанию образцы для представления чисел прописью берутся из файла 1CV7.SPL, который размещен в папке BIN и содержит 5 секций со следующими данными:
{"Speller",
{"Money",
{"Рубль", "Рубля", "Рублей", "Копейка", "Копейки", "Копеек", "М"}},
{"Numbers",
{"Один", "Два", "Три", "Четыре", "Пять", "Шесть", "Семь", "Восемь", "Девять", "Одна", "Две",
"Десять", "Одиннадцать", "Двенадцать", "Тринадцать", "Четырнадцать", "Пятнадцать", "Шестнадцать", "Семнадцать", "Восемнадцать", "Девятнадцать", "Двадцать", "Тридцать", "Сорок", "Пятьдесят", "Шестьдесят", "Семьдесят", "Восемьдесят", "Девяносто", "Сто", "Двести", "Триста", "Четыреста", "Пятьсот", "Шестьсот", "Семьсот", "Восемьсот", "Девятьсот",
"Тысяча", "Тысячи", "Тысяч",
"Миллион", "Миллиона", "Миллионов",
"Миллиард", "Миллиарда", "Миллиардов",
"Триллион", "Триллиона", "Триллионов",
"Нуль"}},
{"Date",
{"Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь",
"Января", "Февраля", "Марта", "Апреля", "Мая", "Июня", "Июля", "Августа", "Сентября", "Октября", "Ноября", "Декабря",
"г.", "Квартал"}},
{"DateRange",
{"Полугодие", "Месяцев"}},
{"WeekDay",
{"Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"}}
}
Замечание. Последний элемент секции Money - это латинская буква М или F (сокращения от male и female), указывающая, какой род (мужской или женский) используется для представления денежных единиц.
Изменить способ вывода числа прописью можно, обратившись к процедуре Пропись, рассмотренной в разд. 2.8.5.5.
2.8.5.3. ФОРМАТИРОВАНИЕ СИМВОЛЬНЫХ ДАННЫХ
Форматная строка при форматировании символьных данных имеет вид "С[Д]", где Д - длина результирующей строки. Если Д больше длины форматируемой строки, то последняя дополняется пробелами справа, если меньше, то в результате сохраняются первые Д символов. Например:
Сообщить(СтрДлина(Формат("ААББВВ", "С10"))); // Напечатает 10
Сообшить(Формат("ААББВВ", "С2")); // Напечатает АА
Форматируемая строка не изменяется, если компонент Д форматной строки отсутствует или на его месте стоит не число. Например:
Сообщшъ(Формат("ААББВВ", "С"))); // Напечатает ААББВВ
Сообщшъ(Формат("ААББВВ", "СК")); // Напечатает ААББВВ
2.8.5.4. ФОРМАТИРОВАНИЕ ДАТ
При форматировании дат форматная строка начинается с буквы Д. Варианты задания форматной строки приведены в табл. 2.11. В ее последнем столбце приводятся результаты форматирования дат 21.12.01 и 05.12.01.
Таблица 2.11
Форматные строки для дат |
Форматная строка |
Вид результата |
Примеры |
"ДДЦММГГ |
дд.мм.гг |
21.12.01 |
"ДДЦММГПТ" |
дд.мм.гггг |
21.12.2001 |
"ДДДММММГПТ" |
ДД месяц прописью ГГГГ г. |
5 Декабря 2001 г. |
"Д(0)ДДММММГГГГ" |
ДД месяц прописью ГГГГ г., если в дне две цифры |
21 Декабря 2001 г. |
|
ОД месяц прописью ГГГГ г., если в дне одна цифра |
05 Декабря 2001 г. |
"ДММММГПТ" |
Месяц прописью ГГГГ г. |
Декабрь 2001 г. |
"ДММММГГ" |
Месяц прописью ГГ г. |
Декабрь 01г. |
"ДММММ" |
Месяц прописью |
Декабрь |
"ДККККГПТ" |
Номер квартала ГГГГ г. |
4 Квартал 2001 г. |
"ДККККГТ" |
Номер квартала ГГ г. |
4 Квартал 01 г. |
"ДКККК" |
Номер квартала. |
4 Квартал |
"ДГГГММДД" |
ГГГММДЦ |
20011205 |
"ДНННН" |
Название дня недели даты; по умолчанию берется из секции WeekDay файла 1CV7.SPL |
Среда |
|
Представление даты не изменяется, если форматная строка не отвечает приведенным в табл. 2.11 требованиям.
28.5.5. ИЗМЕНЕНИЕ СПОСОБА ВЫВОДА ЧИСЕЛ ПРОПИСЬЮ
Осуществляется процедурой Пропись([образец]); в которой параметр образец - это
• либо строка, задающая имя файла образцов прописей;
• либо переменная типа СписокЗначений, содержащая образцы прописей (тип данных СписокЗначений рассмотрен в разд. 3.2);
• либо пустая строка.
: '25.10.02' '25.10.02'
^ '25.10.02'
: '25.10.02' '25.10.02'
: "25.10.02" "123.45"
: "25.10.02"
2452573
2452573
123.45
123.45
= -123.45
123.45
("число - дата") ("строка - дата") ("строка - дата") ("дата - дата")
("дата - строка") ("число - строка") ("строка - строка") ("дата - число") ("дата - число") ("строка - число") ("строка - число") ("строка - число") ("число - число")
дат = Дата(2452573); дат = Дата("25.10.2002"); дат = Дата("25.10.02"); дат = Дата('25.10.2002'); дат = Дата(2002, 10, 25); стр = Строка('25.10.02'); стр = Строка(+123.45); стр = Строка("25.10.02"); чис = Число('25.10.2002') чис = Число('25.10.02'); чис = Число("123.45"); чис = Число("+123.45"); чис = Число("-123.
чис = Число(123.45);
// Имеем: дат =
// Имеем: дат =
// Имеем: стр =
; // Имеем: чис =
45'); // Имеем: чис
//Имеем: чис=
В последнем случае образцы прописей берутся из заданного по умолчанию файла 1CV7.SPL. Также этот файл используется, если параметр образец опущен или если обращений к процедуре Пропись не было.
При задании файла образцов прописей нужно сохранять имеющиеся в файле по умолчанию (1CV7.SPL) секции и последовательность расположения образцов.
При задании параметра образец в виде списка значений в нем можно определять либо все секции, имеющиеся в файле 1CV7.SPL, либо часть из них. В первом случае элементами параметра образец являются 5 списков значений, элементы которых - это образцы представлений числовых данных следующих секций:
• Money;
• Numbers;
• Date;
• DateRange;
• WeekDay.
Порядок задания образцов определен в файле 1CV7.SPL.
Если образец включает не все секции, то в список значений, содержащий образец, в качестве представления заносится название соответствующей секции.
Пример. Формируется список значений сЗнач, содержащий секцию WeekDay, с образцами, отличающимися от приведенных в файле 1CV7.SPL. Далее сЗнач используется в качестве параметра образец процедуры Пропись. С использованием нового образца функцией Формат выводится день недели.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сЗнач, сЗнач2;
ОчиститьОкноСообщений();
сЗнач = СоздатьОбъект("СписокЗначений");
сЗнач2 = СоздатьОбьект(''СписокЗначений'');
// Раздел WeekDay
сЗнач2.ДобавитьЗначение(''Понед'');
сЗнач2.ДобавитьЗначение("Вт.");
сЗнач2.ДобавитьЗначение(''Ср.'');
сЗнач2.ДобавитьЗначение('Четв.");
сЗнач2.ДобавитьЗначение("Пятн.");
сЗнач2.ДобавитьЗначение("Субб.");
сЗнач2.ДобавитьЗначение("Воскр.");
// Параметр образец - список значений, элементы которого также списки значений // Не забываем определить представление "WeekDay" при добавлении в список сЗнач // элемента сЗнач!
сЗнач.ДобавитьЗначение(сЗнач2, "WeekDay");
// Теперь при выводе дней недели будут использоваться названия списка сЗнач2, //добавленного в образец сЗнач Пропись(сЗнач);
Сообщить(Формат('21.12.01', "ДНННН'')); // Напечатает Пяти. Сообщить(формат('05.12.01', "ДНННН")); // Напечатает Ср.
// Возвращаемся к установленному по умолчанию файлу с образцами прописей Пропись("");
Сообщить(Формат('21.12.01', "ДНННН")); // Напечатает Пятница Сообщить(Формат('05.12.01', "ДНННН")); // Напечатает Среда конецПроцедуры // Выполнить
2.9. УПРАВЛЯЮЩИЕ ОПЕРАТОРЫ И КОНСТРУКЦИИ
2.9.1. АЛГОРИТМ КАК СОВОКУПНОСТЬ БАЗОВЫХ СТРУКТУР
Программа и ее отдельные части создаются на основе алгоритмов. Фактически программа - это кодировка некоторого алгоритма или группы алгоритмов. Из этого следует, что до написания кода необходимо разработать и записать (последнее не всегда делается) алгоритм.
Алгоритм - это последовательность действий, либо приводящая к решению задачи, либо поясняющая, почему это решение получить нельзя. Например, отрицательный результат получается при ошибочном задании входных данных.
Алгоритм составляется из отдельных фрагментов, которые могут иметь одну из следующих структур:
• блок операторов и конструкций;
• ветвление;
• цикл.
Блок операторов и конструкций (БОК) - это выполнение одного или нескольких простых или сложных действий. БОК может содержать и ветвления и циклы, которые являются примерами сложных действий. Простым действием является, например, в ы-полнение присваивания или вызов процедуры. Конструкции состоят из нескольких операторов и используются для выполнения управляющих действий, например циклов. Так, конструкция Если ... КонецЕсли состоит из двух операторов: Если и КонецЕсли. Последний оператор конструкции должен завершаться точкой с запятой.
Ветвление - это выбор одного из возможных направлений выполнения алгоритма, осуществляемый в зависимости от значения некоторых условий. Ветвления подразделяются следующие виды:
• если - то;
• если - то - иначе;
• если - то - иначе - если;
• выбор по ключу (в 1С это ветвление не используется, вместо него употребляется "Если - то - иначе - если");
• попытка.
Цикл - это повторное выполнение некоторого БОК с разными, как правило, значениями входящих в БОК переменных. Однократное выполнение БОК цикла называют итерацией. БОК цикла также называют телом цикла.
Различают следующие циклы:
• с параметром;
• пока;
• до.
Последний вид цикла применяется крайне редко; в 1С он отсутствует.
При записи алгоритма составляющие его базовые структуры либо отображаются графически, либо записываются в виде линейных схем. Проиллюстрируем обе эти воз-
можности.
2.9.2. ВЕТВЛЕНИЯ "ЕСЛИ"
В ветвлениях "если - то", "если - то - иначе" и "если - то - иначе - если" для записи условий используется логическое выражение (ЛВ), результатом которого может быть истина (И) или ложь (Л). Графически ветвления проиллюстрирует рис. 2.5.
 |
Рис. 2.5. Ветвления: а - ветвление "если - то"; б - ветвление "если - то - иначе Ветвление "если - то" работает так:
• вычисляется значение ЛВ;
• если оно истинно, то выполняется БОК1;
• если оно ложно, то управление передается БОК2.
Записи ветвления "если - то" в линейной схеме алгоритма:
Х°. Если истинно ЛВ, то [выполнить:]
БОК1
конец если [Х°]. |
В 1С ветвление "если - то" записывается очень похоже: если ЛВ тогда
БОК
1 // Некоторые операторы
конецЕсли;
Ветвление "если - то - иначе" работает так:
• вычисляется значение ЛВ;
• если оно истинно, то выполняется БОК
1
• если оно ложно, то выполняется БОК
2;
• далее управление передается БОК
3.
Запись ветвления "если - то - иначе" в линейной схеме алгоритма:
Х°. Если истинно ЛВ, то [выполнить:]
БОК
1
иначе [выполнить:]
БОК
2
конец если [Х°].
Запись ветвления "если - то - иначе" в 1С: если ЛВ тогда
БОК
1 // Некоторые операторы
иначе
БОК
2 // Некоторые операторы
конецЕсли;
Пример использования ветвлений "если - то" и "если - то - иначе" см. в разд. 1.7.3. Замечание. Если БОК
1 и БОК
2 в ветвлении "если - то - иначе" являются выражениями, то для выбора вычисляемого выражения лучше употреблять функцию, вычисляющую выражение по условию. Ее синтаксис:
результат = ?(ЛВ, выражение,, выражение
2);
Пример:
у = ?(х > 0, Лог(х), х); // Вернет Лог(х), если х >0, или х - в противном случае
Приведенный оператор заменяет следующее ветвление:
если х > 0 тогда у = Лог(х); иначе у = х;
конецЕсли;
Для ветвления "если - то - иначе - если" укажем только способ его записи в 1 С:
если ЛВ
1 тогда
Некоторые операторы Некоторые операторы
Некоторые операторы
Последние два элемента конструкции
являются необязательными
иначеЕсли ЛВ
2 тогда
иначеЕсли ЛВ
к тогда
конецЕсли;
2.9.3. "ПОПЫТКА"
Ветвление Попытка служит для обработки исключений и реализуется в 1С виде следующей конструкции:
попытка
EOKj,
исключение
БОК,
конецПопытки;
В конструкции БОК, - это последовательность операторов, в которых может возникнуть исключение, а в БОК
2 - это последовательность операторов, обрабатывающих исключение.
Напомним, что исключение - это ошибка, возникающая при исполнении программы, например деление на нуль или выход за границы массива. В первом случае система выдаст сообщение "Деление на 0", во втором - "Значение индексного выражения
Работа программы, если не используется обработка исключений, при возникновении ошибки прекращается. Некоторые ошибки, приводящие к останову программы, могут быть, однако, устранены. Например, ошибка блокировки данных, возникающая при обращении к файлу, захваченному в настоящий момент другим приложением, устраняется после завершения работы этого приложения. Другие ошибки, если их игнорировать, не исказят конечного результата. Например, выход за границы массива. В таких случаях целесообразно применить конструкцию Попытка с тем, чтобы при возникновении ошибки выполнить ее обработку, например просто сообщить об ошибке, и продолжить расчеты.
Пример. Вычисляется сумма элементов вектора. В процедуре при обращении к вектору умышленно введена ошибка - выход за границы вектора. Для ее преодоления применяется конструкция Попытка.
процедура Выполнить() // Запускаем процедуру из обработки Проба
перем а[5], ин, сум;
// Инициализация вектора а
а[1] = 0; а[2] = 1.5; а[3] = 2.5; а[4] = -1; а[5] = 7;
// Сумма элементов массива а. Ожидаемый результат: сум = 10 сум = 0;
// Умышленно для иллюстрации работы конструкции Попытка // задаем верхний параметр цикла большим числа элементов вектора а для ин = 1 по 7 цикл
попытка // При выходе за границы вектора
сум = сум + а[ин]; // произойдет обработка исключения;
исключение // исполнение программы не прекратится
Сообщить(ОписаниеОшибки0 + ". Вычисления будут продолжены."); конецПопытки; конецЦикла; // для
Сообщить(”сум = ” + сум); // Напечатает 10
конецПроцедуры // Выполнить
Замечание. Встроенная функция ОписаниеОшибки возвращает описание ошибки в том виде, в каком оно выдается системой в окно сообщений при отсутствии обработки исключений.
Конструкции Попытка могут быть вложенными. В таких случаях при возникновении ошибки ее обработка передается оператору Исключение того уровня вложенности, на котором ошибка возникла. Чтобы передать обработку ошибки оператору более высокого уровня, применяется оператор ВызватьИсключение. Если оператор Вы-зватьИсключение применен, а внешнего обработчика не существует, то произойдет останов программы с выдачей сообщения об ошибке. Последний эффект будет, в частности, получен, если оператор ВызватьИсключение вставить в код вышеприведенного примера перед оператором КонецПопытки.
Пример. Вычисляется сумма элементов вектора. В процедуре при обращении к вектору умышленно введена ошибка - выход за его границы. Для ее преодоления применяется конструкция Попытка. Однако в этот раз в результате применения оператора ВызватьИсключение осуществляется выход из цикла и передача управления внешнему обработчику.
процедура Выполнить() // Запускаем процедуру из обработки Проба
перем а[5], ин, сум;
// Инициализация вектора а
а[1] = 0; а[2] = 1.5; а[3] = 2.5; а[4] = -1; а[5] = 7;
// Сумма элементов массива а. Ожидаемый результат: сум = 10 сум = 0;
// Умышленно для иллюстрации работы конструкций Попытка
// задаем верхний параметр цикла большим числа элементов вектора а
попытка
для ин = 1 по 7 цикл
попытка // При выходе за границы вектора передадим
сум = сум + а[ин]; // управление внешнему обработчику исключений исключение
вызватьИсключение; // Передача управления внешнему обработчику конецПопытки; // внутренней конецЦикла; // для исключение
Сообщить(ОписаниеОшибки() + ". Осуществлен выход из цикла. Работа продолжается"); конецПопытки; // внешней
Сообщить("сум = " + сум); // Напечатает 10
конецПроцедуры // Выполнить
Замечание. Внешний обработчик в данной ситуации, конечно же, избыточен и введен лишь для иллюстрации оператора ВызватьИсключение. При отсутствии внешней конструкции Попытка вместо оператора ВызватьИсключение следует употребить оператор Прервать, предваренный, например, тем же, что и в приведенном примере, вызовом процедуры Сообщить.
2.9.4. ЦИКЛЫ
В цикле "с параметром и" задаются начальное значение параметра к, его конечное значение к и шаг ш - отличная от нуля величина, на которую изменяется значение параметра и после выполнения очередной итерации. В 1С шаг ш всегда принимается равным единице. Параметр п также называют переменной цикла, которая должна быть целочисленной. Параметры ник являются в 1С числовыми выражениями и представляют соответственно нижнюю и верхнюю границы переменной цикла. Если параметр н(к) вычисляется с нецелым значением, то в качестве параметра используется целая часть результата.
Замечание. Параметр цикла часто называют его индексом, для обозначения которого в программах нередко употребляют имя ин или инд.
Графически цикл "с параметром" иллюстрирует рис. 2.6.
 |
Рис. 2.6. Цикл с параметром |
Цикл "с параметром" работает так (случай ш > 0):
1°. Присвоить: п = н.
2°. Если п <= к, то перейти к п. 3°, иначе завершить цикл.
3°. Выполнить БОК.
4°. Присвоить: п = п + ш и перейти к п. 2° (повтор).
Когда ш < 0, п. 2° выглядит так:
2°. Если п > к , то переход к п. 3°, иначе завершить цикл.
Замечания:
1. В цикле "с параметром" приведенные в пп. 1° и 4° операторы в тексте программы не присутствуют, но будут автоматически встроены компилятором в объектный код при компиляции программы.
2. Во многих языках программирования, например в Фортране, в цикле "с параметром" запрещается в теле цикла менять значения переменной цикла и. Изменение параметров н, к и шага ш в теле цикла не отразится на выполнении цикла: цикл будет выполняться с теми значениями параметров, какие они имели до начала первой итерации цикла. В 1С запрет на изменение значения переменной цикла п не действует. Однако следует помнить, что изменение п в теле цикла - это плохой стиль программирования.
Запись цикла "с параметром" в линейной схеме алгоритма:
Х°. С параметром п = н,к,ш [выполнить:]
БОК
конец цикла [с параметром п] | [Х°]. и в 1С:
для п = н по к цикл БОК
конецЦикла;
Цикл Пока выполняется до тех пор, пока истинно некоторое ЛВ. Причем проверка истинности ЛВ выполняется перед началом очередной итерации. Цикл До отличается от цикла Пока тем, что проверка истинности ЛВ осуществляется после выполнения очередной итерации. Графическая интерпретация циклов Пока и До приведена на рис. 2.7.
 |
Рис. 2.7. Циклы: а - цикл Пока; б - цикл До |
Замечание. При работе с циклами Пока и До надо следить, чтобы ЛВ обязательно рано или поздно приняло значение ложь. Иначе произойдет зацикливание - "бесконечное" выполнение операторов цикла.
Запись циклов Пока в линейной схеме алгоритма:
Х°. Пока истинно ЛВ [, выполнить:]
БОК
конец цикла Х°. и в 1С: пока ЛВ цикл
БОК // Некоторые операторы
конецЦикла;
Замечания:
1. Далее при ссылке на циклы будем использовать принятые в 1С имена операторов циклов - Для и Пока.
2. Циклы Для и Пока могут быть вложенными. То есть в теле цикла Для (Пока) могут быть другие циклы Для и/или Пока.
Проиллюстрируем второе замечание примером, записав код вывода групп подряд следующих непериодических констант, сообщающий перед выводом группы ее номер. (Уточним: в примере группа - это подмножество подряд следующих непериодических констант, не имеющее периодических констант. То есть группы разделяются одной и более периодическими константами.)
// Процедура, выводящая группы непериодических констант // Запускается из обработки Проба процедура Выполнить()
перем всегоКонстант, ин, номерГруппы, идеи;
ОчиститьОкноСообщенийО; номерГруппы = 0;
всегоКонстант = Метаданные. Константа();
ин = 1; // Номер константы
пока ин <= всегоКонстант цикл
если Метаданные.Константа(ин).Периодический = 0 тогда номерГруппы = номерГруппы + 1;
Сообщить("Выводится группа с номером " + номерГруппы);
// Вложенный цикл Пока
пока Метаданные.Константа(ин).Периодический = 0 цикл идеи = Метаданные.Константа(ин).Идентификатор;
Сообщить(иден + " " + Константа.ПолучитьАірибут(иден));
ин = ин + 1; // Не забываем перейти к следующей константе
если ин > всегоКонстант тогда
прервать; // Досрочный выход из вложенного цикла
конецЕсли;
конецЦикла; // пока Метаданные.Константа(ин).Периодический = 0 иначе // Имеем периодическую константу
ин = ин +1; // Не забываем перейти к следующей константе
конецЦикла; // пока ин <= всегоКонстант если номерГруппы = 0 тогда
Сообщшъ("В конфигураторе нет непериодических констант"); конецЕсли;
конецПроцедуры // Выполнитъ
2.9.5. О ВЫЧИСЛЕНИИ ЛОГИЧЕСКИХ ВЫРАЖЕНИЙ
В 1С Л В при их оценке всегда вычисляются полностью (по крайней мере в текущей версии). Это создает некоторые неудобства. Так, в последнем примере вложенный цикл Пока было бы лучше записать следующим образом, обойдя применение оператора Прервать:
пока (ин <= всегоКонстант) и (Метаданные. Константа(ин).Периодический = 0) цикл идеи = Метаданные. Константа(ин). Идентификатор;
Сообщитъ(иден + " " + Константа.ПолучитъАтрибут(иден));
ин = ин +1; // Не забываем перейти к следующей константе
конецЦикла; // пока (вложенного)
Однако тогда возникнет ошибка исполнения
пока (ин <= всегоКонстант) и (Метаданные.Константа(ин).Периодический = 0) цикл {В:\ПРОБАБКТ(14)}: Поле агрегатного объекта не обнаружено (Периодический)
Ее природа в том, что на некотором шаге значение переменной ин стало больше значения переменной всегоКонстант. При этом значение ЛВ
(ин <= всегоКонстант) и (Метаданные.Константа(ин).Периодический = 0)
независимо от значения второго выражения отношения будет ложь. Поэтому в принципе вычисление второго выражения отношения избыточно и его можно не выполнять. Но в 1С оно вычисляется, и, поскольку константы с номером ин = всегоКонстант + 1 нет, возникает описанная выше ошибка, приводящая к останову программы.
Рассмотрим теперь конструкцию "если" с ЛВ, состоящим из двух подвыражений отношения, объединенных логической операцией ИЛИ:
если (3 > 2) или (Лог(0) = 1) тогда сообщить("Что-то"); конецЕсли;
Результат этого ЛВ, если первое подвыражение истинно, не зависит от значения второго подвыражения, и, следовательно, оно могло бы не вычисляться. Однако в 1С ЛВ вычисляются полностью, поэтому данный код, поскольку в нем вычисляется 1п0, приведет к ошибке исполнения, о которой 1С сообщит следующим образом:
если (3 > 2) или (Лог(0) = 1) тогда
{В:\1С?7ЛСО№10МБЩБХТГОКМВ\ПГОБАБКТ(3)}: Деление на 0
2.9.6. ПРИМЕР ЗАПИСИ АЛГОРИТМА
Обратимся для иллюстрации правил записи алгоритма к ранее рассмотренной задаче вывода списка непериодических констант, для которых в метаданных задан синоним (разд. 1.7.3). В этой задаче сведения одного вида (идентификатор, синоним и значение) выводятся для различных констант. Повторное выполнение одних и тех же действий ре а-лизуется в виде цикла. Здесь наиболее уместен цикл "с параметром", в котором в качестве параметра выступает номер константы. Для учета условий, ограничивающих вывод данных, используем условие "если - то". Алгоритм решения задачи можно отобразить в виде следующей линейной схемы:
1. Начало.
// Число констант в конфигурации
2. всегоКонстант = Метаданные.КонстантаО
// Переменная флагВывода принимает значение 1, если напечатаны данные // хотя бы об одной константе
3. флагВывода = 0;
4. С параметром ин= 1, всегоКонстант выполнить:
4.1. Если константа с номером ин непериодическая, то // Синоним константы с номером ин син = Металанные.Константа(ин). Синоним;
4.1.1. Если син не является строкой нулевой длины, то флагВывода = 1;
Вывести идентификатор, синоним и значение константы с номером ин. конец если 4.1.1. конец если 4.1. конец цикла 4.
5. Если флагВывода = 0, то
Сообщить: "Нет непериодических констант с непустым синонимом." конец если 5.
6. Конец.
Код приведенного фрагмента на языке 1С будет незначительно отличаться от кода процедуры Выполнить примера 3 разд. 1.7.3.
Условия 4.1 и 4.1.1 можно объединить таким образом:
4.1. Если константа с номером ин непериодическая и константа имеет синоним, то флагВывода = 1;
Вывести идентификатор, синоним и значение константы с номером ин. конец если 4.1.
Такому объединению отвечает следующий код на 1С:
если (Метаданные.Константа(ин).Периодический = 0) и
(ПустаяСтрока(Метаданные.Константа(ин). Синоним) = 0) тогда флагВывода = 1;
син = Метаданные.Константа(ин). Синоним; идеи = Метаданные.Константа(ин).Идентификатор; значен = Константа. ПолучитьАтрибут(иден);
Сообщить(иден + " - " + син + " - " + значен); конецЕсли;
Его недостаток в том, что дважды извлекается информация о синониме, что связано с дополнительными временными издержками; с другой стороны, он компактнее первого варианта.
Замечание. Встроенная функция ПустаяСтрока(строка) вернет 1, если ее аргумент строка имеет нулевую длину или состоит из одних пробелов, в противном случае функция вернет 0.
Любой цикл с параметром можно, конечно же, заменить циклом Пока, например
ин = 1; // Подготовка к циклу Пока
пока ин <= всегоКонстант цикл
// Тело цикла см. в вышеприведенном цикле "с параметром"
// Добавляем в тело цикла оператор увеличения номера константы // Без этого оператора произойдет зацикливание ин = ин+ 1; конецЦикла;
2.9.7. ПРЕРЫВАНИЯ ЦИКЛА. ОБЪЕДИНЕНИЕ УСЛОВИЙ
Выйти из цикла и передать управление на первый следующий за циклом выполняемый оператор можно, применив оператор Прервать. Чтобы пропустить часть операторов цикла и перейти к следующей итерации, следует использовать оператор Продолжить. При этом управление передается оператору начала цикла - оператору Для или Пока. Операторы Прервать и Продолжить отдельно не применяются, а встраиваются в конструкции "если".
Пример. Сообщить значение первой непериодической константы числового типа.
// Процедура, выводящая значение первой непериодической константы числового типа // Запускается из обработки Проба процедура Выполнить()
перем всегоКонстант, флагВывода, ин, идеи;
ОчиститьОкноСообщенийО;
// флагВывода примет значение 1, если будет обнаружена // непериодическая константа числового типа флагВывода = 0;
всегоКонстант = Метаданные.КонстантаО; для ин = 1 по всегоКонстант цикл
если Метаданные.Констанга(ин).Периодический = 1 тогда
продолжить; // Передаем управление оператору Для
конецЕсли;
если Метаданные.Консташа(ин).Тип = "Число" тогда идеи = Метаданные.Констата(ин).Идентификатор;
Сообщить(иден + "" + Константа.ПолучитьАтрибут(иден)); // БалансДней 1 флагВывода = 1;
прервать; // Досрочный выход из цикла Для
конецЕсли; конецЦикла; // для если флагВывода = 0 тогда
Сообщить("В конфигураторе нет непериодических констант числового типа."); конецЕсли;
конецПроцедуры // Выполнить
Замечание. Иногда программисты в цикле Для вместо оператора Прервать прибегают к изменению значения переменной цикла ин. Так, в нашем случае оператор Прервать мог быть заменен оператором
ин = всегоКонстант;
Такие действия, однако, классифицируются как плохой стиль программирования.
Некоторые программисты считают, что операторы прерывания цикла (в 1С это Продолжить и Прервать) ухудшают структуру программы, и поэтому по возможности отказываются от их употребления. Взамен используется объединение условий.
Последуем и мы принципам структурного программирования, написав решающий вышеприведенную задачу код, использующий объединение условий. В этом коде нам придется отказаться от цикла Для, заменив его циклом Пока.
// Процедура, использующая объединение условий и выводящая значение первой // непериодической константы числового типа. Запускается из обработки Проба процедура Выполнить()
перем всегоКонстант, флагВывода, ин, идеи;
ОчистигьОкноСообщенийО;
// флагВывода примет значение 1, если будет обнаружена // непериодическая константа числового типа флагВывода = 0;
всегоКонстант = Метаданные.КонстантаО;
ин = 1; // Номер константы
пока (ин<= всегоКонстант) и (флагВывода = 0) цикл
если (Метаданные.Константа(ин).Периодический = 0) и (Метаданные.Константа(ин).Тип = "Число") тогда идеи = Метаданные.Константа(ин).Идентификатор;
Сообщить(иден + " " + КонстантаПолучитъАтрибут(иден)); флагВывода = 1; конецЕсли;
ин = ин + 1; // Не забываем перейти к следующей константе
конецЦикла; // для если флагВывода = 0 тогда
Сообщить("В конфигураторе нет непериодических констант числового типа."); конецЕсли;
конецПроцедуры // Выполнить
В приведенном коде объединение условий использовано при записи ЛВ дважды: (ин <= всегоКонстант) и (флагВывода = 0)
(Метаданные.Констата(ин).Периодический = 0) и (Метаданные.Константа(ин).Тип = "Число") Это позволило нам исключить из процедуры операторы Продолжить и Прервать.
2.9.8. ПЕРЕХОД ПО МЕТКЕ
Выполняется оператором Перейти метка;
где метка - это имя, начинающееся с тильды (знака ~), например ~М1.
Этот оператор неприемлем для сторонников структурного программирования. Однако есть ситуации, кода он полезен, например для досрочного выхода из вложенного цикла.
Пример. Записать, код вывода групп подряд следующих непериодических констант, сообщающий перед выводом группы ее номер, завершая вывод, обнаружив непериодическую константу типа Календарь.
// Процедура, выводящая группы непериодических констант
// Завершается либо при обнаружении непериодической константы типа Календарь,
// либо после вывода всех групп. Запускается из обработки Проба процедура Выполнить()
перем всегоКонстант, ин, номерГруппы, иден;
ОчистшъОкноСообщенийО; номерГруппы = 0;
всегоКонстант = Метаданные.КонстантаО;
ин = 1; // Номер константы
v
пока ин <= всегоКонстант цикл
если Метаданные.Константа(ин).Периодический = 0 тогда номерГруппы = номерГруппы + 1;
Сообщить("Выводится группа с номером " + номерГруппы);
// Вложенный цикл Пока
пока Метаданные.Константа(ин).Периодический = 0 цикл если Метаданные.Константа(ин).Тип = "Календарь" тогда перейти ~М1; // Выход из всех циклов
конецЕсли;
иден = Метаданные.Константа(ин).Идентификатор;
Сообщитъ(иден + "" + Константа.ПолучиіъАтрибут(иден));
ин = ин + 1; // Не забываем перейти к следующей константе
если ин > всегоКонстант тогда
прервать; // Досрочный выход из вложенного цикла
конецЕсли;
конецЦикла; // пока Метаданные.Константа(ин).Периодический = 0 иначе // Имеем периодическую константу
ин = ин + 1; // Не забываем перейти к следующей константе
конецЕсли;
конецЦикла; // пока ин <= всегоКонстант // Располагаем после метки ~М1 двоеточие
~М1: // Сюда передается управление оператором Перейти ~М1;
если номерГруппы = 0 тогда
Сообщить("В конфигураторе нет непериодических констант."); конецЕсли;
конецПроцедуры // Выполнить
Замечание. В данной задаче метку ~М1 нельзя расположить перед оператором конецЦикла:
~М1: конец цикла; // пока ин <= всегоКонстант
поскольку такое использование метки не приводит к выходу из цикла, а передает управление на оператор Пока внешнего цикла. В конкретном случае результатом такого размещения метки будет зацикливание программы.
Разумеется, задачу можно решить и без использования оператора, введя флаг обнаружения константы типа Календарь и применив, например, объединение условий. При желании соответствующий код вы можете составить самостоятельно.
2.10. ПОЛЬЗОВАТЕЛЬСКИЕ ПРОЦЕДУРЫ И ФУНКЦИИ
2.10.1. ПРОГРАММИРОВАНИЕ "СВЕРХУ ВНИЗ”
Разработка алгоритмов и программ осуществляется, как правило, по принципу "сверху вниз".
Суть такого подхода состоит в разбиении исходной задачи на ряд более простых задач - фрагментов - и последующей работе с ними.
При разбиении задачи на фрагменты надо придерживаться следующей схемы:
1. Проанализировать задачу и выделить в ней фрагменты.
2. Отобразить процесс разбиения в виде блок-схемы или линейной схемы и пронумеровать в ней фрагменты.
3. Установить между выделенными фрагментами связи: для каждого фрагмента определить, какие данные он получает (входные данные) и какие данные возвращает (выходные данные). Связи между фрагментами называются интерфейсом.
4. Рассмотреть далее каждый фрагмент самостоятельно; разработать для него алгоритм и записать его либо в виде линейной схемы, либо в виде блок-схемы. При необходимости подвергнуть фрагмент разбиению на более мелкие фрагменты. Такое разбиение продолжать до тех пор, пока не будут получены фрагменты, программирование которых не составляет особых затруднений.
5. Оформить выделенные фрагменты в виде программных компонентов или БОК.
При таком подходе программу можно рассматривать как совокупность фрагментов, которые, принимая некоторые данные, вырабатывают результат и передают его другому фрагменту и так вплоть до завершения вычислений.
Составляемые для фрагментов линейные схемы алгоритмов (разд. 2.8) сопровождаются заголовком и описанием интерфейса, отражающим состав входных и выходных данных.
В 1С для реализации фрагментов можно использовать программные компоненты: основную программу модуля, процедуры модуля и его функции.
Фрагмент алгоритма, как правило, оформляется в виде функции, если в результате выполненных в нем вычислений возвращается единственный скаляр. Если же фрагмент возвращает в вызывающий фрагмент в качестве результата несколько значений, в том числе и в виде массива, или не возвращает результатов, н апример осуществляет вывод данных в файл, то он оформляется в виде процедуры.
2.10.2. СТРУКТУРА ПРОЦЕДУР И ФУНКЦИЙ
Процедуры и функции имеют схожую структуру:
Процедура | Функция Имя([[3нач] парам, = [значение*]], ...,
[[Знач] парам
п = [значение] ]) [Экспорт]
[неисполняемые операторы объявления переменных]
[исполняемые операторы]
КонецПроцедуры | КонецФункции
Ключевое слово, или атрибут, Экспорт указывается для процедур и функций, располагаемых в глобальном модуле (разд. 1.6), в том случае, если их надо сделать доступными для вызова в модулях форм.
Процедуры вызываются в виде отдельного оператора с соблюдением следующего синтаксиса:
Имя_процедуры([парам], ..., [парам
в]);
Функции, как правило, вызываются из выражений, но могут, так же как и процедуры, вызываться в виде отдельно оператора:
Имя_функции([парам
І],..., [парам]);
Функция, если выход из нее осуществляется не в результате выполнения оператора Возврат выражение;
а по оператору КонецФункции возвращает число 0.
Функция, в которой нет оператора Возврат выражение;
всегда возвращает нуль.
Замечание. При программировании функции следует выходить из нее по оператору
Возврат выражение;
даже если выражение - это константа нуль. Например, функции фІ и ф2
функция ф2(а)
если а > 0 тогда
возврат 2 * конецЕсли; конецФункции // ф2
функция ф1(а)
если а > 0 тогда
а;
возврат 2 * а;
иначе
возврат 0; конецЕсли; конецФункции // ф1
возвращают одинаковый результат, однако вариант с фІ отвечает принятому для функций стилю программирования, чего нельзя сказать о функции ф2. Впрочем, в данной ситуации функцию ф1 лучше записать так:
функция ф1ф)
возврат ?(а > 0, 2 * а, 0); конецФункции // ф1
Процедуры и функции могут вызываться только из тех процедур и функций модуля, ранее которых расположены либо они сами, либо их предварительное описание (разд. 1.4.4). Например, в модуле с кодом
функция ф1(а)
возврат ?(а > 0, 2 * а, 0); .конецФункции // ф1
// Предварительное описание процедуры п\
процедура п 1 (д) далее
// б= 15; функция ф1 вызывается из выражения // б = 35; б - фактический параметр процедуры п1
// д - фактический параметр процедуры n1 // д = 4 * 7.5 + 5 = 35
процедура Выполнить() перем б; б = 2.5 * ф1(3); п1(б);
Сообщить(б);
конецПроцедуры // Выполнить
функция ф2(с) возврат с / 2; конецФункции // ф2
процедура п1(д) д = 4*ф2(д) + 5; конецПроцедуры // п1
из процедуры Выполнить можно вызвать функцию ф1 и процедуру nl, но нельзя вызвать функцию ф2.
Замечания:
1. Предварительное описание процедуры (функции) должно совершенно точно дублировать заголовок процедуры (функции). Так, не допускаются расхождения имен параметров, и если заголовок процедуры (функции) снабжен ключевым словом Экспорт, то оно должно присутствовать и в тексте предварительного описания перед ключевым словом Далее. Например: процедура п3(д1, д2) экспорт далее // Предварительное описание процедуры пЗ
2. Перечень имен процедур и функций модуля можно просмотреть, нажав, находясь
, М
в конфигураторе, на иконку на панели инструментов Текстовый редактор. Так, для вышеприведенного набора процедур и функций, если их разместить, например, в модуле обработки Проба, мы получим приведенный на рис. 2.8 список (сортировка имен не задана).
 |
Рис. 2.8. Окно вывода списка процедур и функций модуля |
На начало любой процедуры (функции) или на ее предварительное описание можно переместиться, выбрав в вышеприведенном окне необходимую строку и нажав на кнопку Перейти.
2.10.3. ПАРАМЕТРЫ ПРОЦЕДУР И ФУНКЦИЙ
Обмен данными между программными компонентами 1С осуществляется через глобальные объекты, переменные модуля (разд. 1.4.4), диалога (разд. 1.5) и параметры процедур и функций. Дополнительно от функции можно получить и использовать в выражении возвращаемое ею значение.
Параметры, используемые при вызове процедуры или функции, называются фактическими. Так, в выражении, стоящем в правой части оператора присваивания
д = 4 * ф2(д) + 5; // д = 4 * 7.5 + 5 = 35
из процедуры п\ предшествующего раздела параметр д функции ф2 является фактическим.
Параметры, стоящие в заголовке процедуры (функции), в том числе и в заголовке, присутствующем в тексте предварительного описания, называются формальными. Таким является, например, параметр с в следующем заголовке:
функция ф2(с) // с - формальный параметр функции ф2
При вызове процедуры (функции) между фактическими и формальными параметрами устанавливается соответствие: формальный параметр с номером к адресует фактический параметр (или его копию) с номером к.
Рассмотрим процедуру п3 с тремя формальными параметрами а, б и в. Пусть по назначению первый параметр будет входным, то есть передающим данные в процедуру, второй - выходным, то есть возвращающими данные в вызывающую программу, а третий - входным-выходным. Формальные параметры используются в процедуре как обычные переменные. Объявлять формальные параметры в теле процедуры посредством оператора Перем нельзя.
// с - промежуточная переменная процедуры п3
// Определяем значения параметров б и в
процедура пЗ(а, б, в) перем с; с = 3 * а; б = с - в - 2; в = в + б + с/3; конецПроцедуры // пЗ
Обратимся к иЗ из процедуры Выполнить обработки Проба, использовав в качестве фактических параметров переменные а1,а2 и а3.
процедура Выполнить() перем а, а2, аЗ;
ОчистшъОкноСообщенийО;
а=1;
аЗ = 3;
пЗ(а, а2, аЗ); // Вызов процедуры п3
Сообщить("а2 = " + а2 + "; аЗ = " + аЗ); конецПроцедуры // Выполнить
При таком вызове формальному параметру а процедуры п3 соответствует фактический параметр а, формальному параметру б фактический параметр а2 и формальному параметру в - фактический параметр а3. Понятно, что при вызове параметр а получит значение 1, а параметр в - значение 3. Параметр б - будет иметь пустое значение. Как видно из примера, имена формальных и фактических параметров могут и совпадать и различаться.
Замечание. Из всех присутствующих в процедуре Выполнить переменных обязательно объявление только переменной а2, в противном случае ее нельзя использовать в качестве фактического параметра процедуры п3, или - более широко - операндом любого выражения.
После исполнения п3 в окне сообщений обнаружим следующий результат: а2 = -2; а3 = 2
Приведенное нами деление параметров на входные, выходные и входные-выход-ные является условным, вытекающим из способа их употребления в программе. На месте любого фактического параметра может стоять константа. Например, вызов
п3(1, а2, аЗ); // Первый фактический параметр - константа
полностью эквивалентен вышеприведенному.
Более того, константа может быть и на месте третьего параметра:
п3(1,а2,3);
хотя соответствующий ему формальный параметр меняется в теле процедуры иЗ.
В общем случае на месте фактического параметра может быть любое правильно построенное выражение. Например:
п3(3 * а * а, а2, 3); // На месте первого параметра выражение 3 * а * а
Примеры с вызовом п3 показывают, что при выходе из процедуры фактический параметр, если он является переменной, принимает значение формального параметра. В этом случае говорят, что фактические параметры передаются по ссылке (формальный параметр адресует фактический параметр непосредственно). Можно, однако, установить и иной способ передачи параметров - по значению. Для этого в списке формальных параметров перед параметром, передаваемым по значению, следует поставить ключевое слово (атрибут) Знач, например
процедура п3(а, б, знач в) конецПроцедуры // п3
В этом случае формальный параметр адресует копию фактического параметра и изменения формального параметра не отражаются на значении фактического. Действительно, обратившись к модифицированной процедуре п3
перем а2; аЗ = 3;
// Параметр а2 передается по ссылке, а параметр а3 - по значению п3(1, а2, аЗ); // Вызов процедуры п3
Сообщить("а2 = " + а2 + "; аЗ = " + аЗ);
найдем в окне сообщений текст а2 = -2; аЗ = 3
Как и ожидалось, значение а3 осталось без изменений.
По значению параметры передаются, если есть необходимость защитить фактический параметр от изменений в процедуре или функции. Рассмотрим следующий код:
функция ф1(а) а = 2 * а; возврат а;
конецФункции // ф1
функция ф2(знач а) а = 2 * а; возврат а;
конецФункции // ф2
процедура Выполнить()
ОчиститьОкноСообщенийО;
х=1;
Сообщить(ф1(х) * х * ф1(х)); Сообщить(ф1(х) * ф1(х) * х); х = 1;
Сообщить(ф2(х) * х * ф2(х)); Сообщить(ф2(х) * ф2(х) * х); конецПроцедуры // Выполнить
Из примера видна разница между передачей параметров по ссылке (функция ф1) и передачей параметров по значению (функция ф2).
Замечание. Системные константы (РазделительСтраниц, РазделительСтрок и Сим-волТабуляции) при использовании их в фактических формальных параметрах воспринимаются как передаваемые по ссылке переменные. Эту неточность можно поправить, передавая их, если в этом есть необходимость, в программные компоненты по значению.
Формальные параметры процедур и функций являются необязательными. То есть соответствующие им фактические параметры могут быть опущены. Следующие за ними запятые должны быть при этом сохранены. Например, к вышеприведенной процедуре п3 можно обратиться, опустив все, кроме последнего, параметры:
п3(, ,аЗ);
При таком вызове и такой организации процедуры п3 в выражениях, где присутствуют формальные параметры а и б, используются пустые значения. Можно, однако, в формальные параметры установить значения по умолчанию, которые будут использоваться в выражениях при отсутствии соответствующих им фактических параметров. Для этого используется следующий синтаксис заголовка процедуры:
процедура п3(а = 1, б = -2, в = 3)
перем с; // с - промежуточная переменная процедуры п3
с = 3*а;
б = с - в - 2; // Определяем значения параметров б и в
в = в + б + с/3; конецПроцедуры // п3
Теперь, когда для последнего формального параметра в задано значение по умолЛ чанию, можно, вызывая пЗ, опустить и соответствующий ему фактический параметре не сохраняя предшествующую ему запятую:
п3(1,а2); // а2 = -2 (верно!)
Если же запятая сохранена, то процедура п3 вернет иное, ошибочное значение а2:
п3(1,а2,); // а2 = 1 (ошибка!)
Поскольку компилятор ошибку не отслеживает, что в общем-то странно, нужно придерживаться общего правила обращения к процедуре (функции) без последних параметров: "Если процедура (функция) вызывается без последних параметров, то разделяющие их запятые и запятая, отделяющая эти параметры от присутствующего фактического параметра, опускаются". Например:
// Процедура п3 вызвана без двух последних параметров п3(а);
При вызовах процедур переменные, используемые как фактические параметры, могут менять свой тип. Например:
процедура п4(а) а = "строка"; конецПроцедуры // п4
процедура Выполнить()
ОчиститьОкноСообщений(); а= 1;
Сообщить(ТипЗначенияСтр(а)); |
// |
Число |
п4(а);
Сообщить(ТипЗначенияСтр(а)); |
// |
Строка |
конецПроцедуры // Выполнить |
|
|
Напомним, что формальными параметрами могут быть не только скалярные переменные произвольного типа, но и массивы (разд. 2.6). В этом случае соответствующие фактические параметры также должны быть массивами.
Замечание. Формальные параметры могут иметь агрегатный тип данных, в чем мы смогли убедиться, например, в разд. 1.13, рассматривая контекст обработки. Соответствующие фактические параметры в этом случае должны иметь тот же тип.
2.10.4. ВЛОЖЕННЫЕ ВЫЗОВЫ ПРОЦЕДУР И ФУНКЦИЙ
Любая процедура или функция может содержать вызовы иных процедур и функций, но не может вызвать сама себя явно или через другую процедуру (функцию). Наличие такого вызова приведет к "зависанию" программы. Например:
процедура п6(а) далее
процедура п5(а) // Процедура п5 вызывает сама себя
а = 2 * а; // из процедуры п6. В результате имеем
п6(а); // зависание программы
конецПроцедуры // п5
процедура п6(а) а = -а; п5(а);
конецПроцедуры // п6
процедура Выполнить()
Предупреждение("Сейчас программа зависнет.
| Для продолжения вычислений нажмите Esc.");
а=1;
п5(а);
конецПроцедуры // Выполнить
2.10.5. ОПЕРАТОР ВОЗВРАТ
Как мы видели, функция возвращает результат выражения оператора Возврат выражение;
Такой оператор может быть использован в функции неоднократно. Однако его можно разместить и в процедуре (обычно внутри конструкций "если" или Попытка). При этом выражение должно быть опущено. Например:
процедура п7(а, б) если а <= 0 тогда
Сообщить("Неверное значение аргумента функции Лог."); возврат; // выражение опущено
конецЕсли; б = Лог(а);
конецПроцедуры // п7
Впрочем, лучше обойтись без оператора Возврат, применив ветвление "если-то-иначе":
процедура п8(а, б) если а <= 0 тогда
Сообщить("Неверное значение аргумента функции Лог."); иначе
б = Лог(а); конецЕсли; конецПроцедуры // п8
2.11. ВЫВОДЫ
1. В 1С переменные могут быть простыми или структурированными. Простыми являются числовые, символьные переменные и переменные типа Дата (скалярные или массивы). Сложной структурой обладают переменные агрегатных типов данных.
2. Неопределенные переменные всех типов имеют пустое значение.
3. Константы могут быть числового, символьного типа или типа Дата. Нельзя задать именованные константы, массив - константу и константу агрегатного типа данных. Среди символьных констант 3 являются системными. Нет констант со значениями истина и ложь.
4. В выражении 1С можно употреблять данные различных типов. При вычислении выражения автоматически выполняются преобразования типов данных. Также для преобразования типов данных можно применить встроенные функции Дата, Строка и Число. Тип выражения определяется типом первого операнда.
5. Все операции в выражениях 1С выполняются слева направо.
6. Логические операции имеют более высокий приоритет, чем операции отношения, что нужно учитывать при записи логических выражений.
7. Логические выражения нельзя размещать в правой части оператора присваивания, использовать в качестве фактических параметров процедур и функций и в выражении; оператора Возврат. Их место - это конструкции "если", Для, Пока и функция ?.
8. Логические выражения, состоящие из нескольких подвыражений, всегда вычисляются полностью, несмотря на то, что их результат может быть известен до оценки последнего подвыражения.
9. Массивы могут быть только одномерными. Индекс первого элемента массива всегда равен единице. Элементы массивов могут быть разных типов, в том числе; и агрегатных.
10. Для управления вычислениями в языке предусмотрены ветвления "если" и Попытка, циклы "с параметром" и Пока, операторы прерывания цикла, оператор перехода и оператор выхода из процедуры (функции).
11. Структура программы улучшается, если в ней вместо операторов прерывания цикла и перехода использовать объединение условий.
12. Фактические параметры процедур и функций, если они не являются константами и им не предшествует ключевое слово Знач, передаются по ссылке, в противном случае - по значению.
13. Фактические параметры процедур и функций являются необязательными. При oil сутствии фактического параметра используется установленное для него по умолчанию значение, если оно задано, либо пустое значение - в противном случае.
14. Формальные параметры процедур и функций могут быть скалярами и массивами-любого типа, в том числе и агрегатного.
15. Функция может вызываться, как и процедура, в виде отдельного оператора. При этом возвращаемое ею значение игнорируется.
16. Предварительное описание процедуры (функции), приведенное в начале модуля после объявления его переменных, снимает ограничение на место расположения, процедуры (функции) в теле модуля.
Содержание раздела