Лямбда-функции на встроенном языке 1С
Анонимная функция средствами 1С. Пророчества грядущих функций первого класса и ООП. Другие смелые заявления.
- Описание
- Подробнее
Описание
«Анонимные функции, функции как переменные, методы для структур и соответствий, классы/прототипы, наследование! Где это всё?!» — спросите вы меня. И я уверенно отвечу: «Здесь». В этой теме ключ ко всему. Решение небольшое, элегантное, исключительно на встроенном языке 1С и как прививка от коронавируса: молодое, обнадеживающее, многообещающее, но еще не протестированное на массах. Поэтому прошу пока воспринимать всё, как альфа-версию, или даже, как концепцию. Кстати, под словом "Функция" здесь и ниже понимаются и процедуры тоже.
Имея опыт программирования на Python и JavaScript, страдаю, когда в 1С функция не может быть объектом первого класса. То есть, функцию нельзя поместить в переменную. Не результат выполнения функции, а саму функцию. Это лишает возможности передавать её, как параметр, в другие функции или программно создавать объекты c методами. Мы не можем ждать милости от 1С, и добавим нужные механизмы сами!
Материал будет разбит на несколько публикаций. Сегодня рассмотрим основу всей затеи — анонимную функцию.
Анонимные функции
Их еще называют лямбдами (λ). В отличие от привычных функций не имеют имен и определены непосредственно в месте вызова. В остальном точно такие же. Есть случаи, когда их удобнее использовать, чем именованные. Забегая вперед, покажу пару примеров.
//Каждое четное число в массиве умножить на 3
ForEach(Массив, "Если _1 % 2 = 0 Тогда Возврат _1 * 3; КонецЕсли;");
//Отобрать элементы, состоящие из заглавных букв:
НовыйМассив = Filter(Массив, "Возврат _1 = ВРЕГ(_1);");ForEach и Filter — обычные функции. Как именно они написаны, покажу ниже. Сейчас важно отметить, что они обрабатывают массив с помощью анонимных функций (второй параметр). Это, во-первых, позволяет сократить код без потери читаемости, и, во-вторых, хранить и передавать тело анонимной функции куда нужно.
Пару дней назад я захотел в режиме предприятия написать произвольный код в поле ввода, нажать на кнопку, и чтобы этот код выполнился над списком отобранных объектов. Должен признаться, иногда я тайком использую команды Выполнить/Вычислить и в этот раз на них рассчитывал. Каково же было мое изумление, когда узнал, что эти конструкции не понимают таких важных вещей как: Возврат, Процедура, Функция! Тогда я создал функцию Lambda, которая умеет выполнять код с возвратами.
Lambda(Код, [Аргументы: _1, _2, … _n])
Суть такова. В эту функцию подается код в виде строки и аргументы по необходимости. К аргументам можно обращаться по номерам с подчеркиванием (например, _1). К сожалению, из-за особенности языка 1С максимальное количество аргументов определено заранее (в данных примерах — максимум 4). Все возвраты перед выполнением заменяются на конструкцию с использованием б-гомерзких (да будут они преданы забвению) операторов goto. Таким образом, результат возврата помещается в служебную переменную (ProgmaLambdaResult) и тут же осуществляется переход к концу функции Lambda, где происходит обычный возврат результата. В тексте переданного кода для повышения читаемости допускается заменять две двойные кавычки на символ ` (на клавиатуре, где Ё). Код считается "скомпилированным", если первый символ #.
//Пример использования:
// Lambda вызывается с тремя параметрами:
// Код,
// _1 = СписокОбъектов
// _2 = "Слава Тьюрингу!"
// Результат (Истина или Ложь) вернется в переменную ЕстьПрославлениеТьюринга
//
ЕстьПрославлениеТьюринга = Lambda("
|СтрокаПоиска = ВРЕГ(_2);
|Для каждого Значение из _1 Цикл
| Если Найти(ВРЕГ(Значение.Наименование), СтрокаПоиска) <> 0 Тогда
| Возврат Истина;
| КонецЕсли;
|КонецЦикла;
|Возврат Ложь;
|", СписокОбъектов, "Слава Тьюрингу!"
);Вот так это сейчас реализовано:

