Skip to content
/ lambdas Public

API для реализации функциональных интерфейсов для OneScript

License

Notifications You must be signed in to change notification settings

sfaqer/lambdas

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

lambdas

Лямбдас это библиотека для реализации функциональных интерфейсов в ваших библиотеках

How to

Синтаксис лямбда выражения:

Поддерживаются следующие варианты синтаксиса лямбда выражений:

// 1
"(ПараметрПервый, ПараметрВторой) -> { Возврат ПараметрПервый + ПараметрВторой }"

// 2
"(ПараметрПервый, ПараметрВторой) ->  Возврат ПараметрПервый + ПараметрВторой"

// 3
"ПараметрПервый, ПараметрВторой -> { Возврат ПараметрПервый + ПараметрВторой }"

// 4
"ПараметрПервый, ПараметрВторой -> Возврат ПараметрПервый + ПараметрВторой"

Простой пример

Допустим, у вас есть библиотека, в рамках которой вы хотите позволить потребителю удалять элементы из массива по некоторому условию.

Вы добавляете метод:

// МояКласснаяБиблиотека.os

Процедура УдалитьПоУсловию(Условие) Экспорт

    Действие = Лямбда.Выражение(Условие)
        .ВДействие();

    Для каждого Элемент из Коллекция Цикл

        Если Действие.Выполнить() Тогда
            Коллекция.Удалить(Элемент);
        КонецЕсли;

    КонецЦикла;

КонецПроцедуры

В данном примере вы получаете Действие на метод, который был создан по переданному выражению, и вызов вашего метода теперь может выглядеть вот так:

// ПотребительМоейКласснойБиблиотеки.os

Процедура Удалить()

    // Удалим из коллекции все элементы которые больше или равны двум
    МояКласснаяБиблиотека.УдалитьПоУсловию("Элемент -> Возврат Элемент >= 2");

КонецПроцедуры

Интерфейсы

Для лямбда выражения можно указать функциональный интерфейс который она будет реализовывать, эта возможность преследует две цели

  1. Проверить что переданное выражение соответствует вашим ожиданиям, Функция это или Процедура, и количество параметров
  2. Предоставить возможность не писать возврат в однострочных лямбда выражениях вашим потребителям, если это функция

В составе библиотеки поставляет ряд функциональных интерфейсов (в модуле ФункциональныеИнтерфейсы):

  1. Вызываемый - Функция Вызвать без параметров
  2. УниФункция - Функция Применить с одним параметром
  3. БиФункция - Функция Применить с двумя параметром
  4. ТриФункция - Функция Применить с тремя параметром
  5. Запускаемый - Процедура Запустить без параметров
  6. УниПроцедура - Процедура Принять с одним параметром
  7. БиПроцедура - Процедура Принять с двумя параметрами
  8. ТриПроцедура - Процедура Принять с тремя параметрами

Так же можно установить произвольный ИнтерфейсОбъекта для создания метода по нему

Если интерфейс не был передан явно, то будет предпринята попытка автоматически подобрать один из интерфейсов из списка выше, в зависимости от количества параметров лямбда выражения и наличия возврата значения в его тексте

Например:

// МояКласснаяБиблиотека.os

Процедура Сортировать(СравнениеЗначений) Экспорт

    Интерфейс = Новый ИнтерфейсОбъекта();
    Интерфейс.ФункцияИнтерфейса("Сравнить", 2);

    Компаратор = Лямбда.Выражение(СравнениеЗначений)
        .Интерфейс(Интерфейс)
        .ВОбъект();

    Для каждого Элемент Из Коллекция Цикл

        РезультатСравнения = Компаратор.Сравнить(Элемент, СледующийЭлемент);

        Если РезультатСравнения > 0 Тогда
            // ...
        ИначеЕсли РезультатСравнения < 0 Тогда
            // ...
        Иначе
            // ...
        КонецЕсли;

        // Алгоритм сортировки

    КонецЦикла;

КонецПроцедуры

Тут мы использовали метод ВОбъект для получения сценария, который реализует наш переданный интерфейс, и обратились по имени метода, который мы отразили в интерфейсе.

Вызов метода:

// ПотребительМоейКласснойБиблиотеки.os

МояКласснаяБиблиотека.Сортировать("Первый, Второй -> 
    | Если Первый > Второй Тогда
    |    Возврат 1;
    | ИначеЕсли Второй > Первый Тогда
    |    Возврат -1;
    | Иначе
    |    Возврат 0;
    | КонецЕсли;"
);

Пример необязательного возврата:

// МояКласснаяБиблиотека.os

Процедура Заменить(Массив, Выражение) Экспорт

    Действие = Лямбда.Выражение(Выражение)
        .Интерфейс(ФункциональныеИнтерфейсы.УниФункция())
        .ВДействие();

    Счетчик = 0;

    Для Счетчик = 0 По Массив.ВГраница() Цикл
        Массив.Установить(Счетчик, Действие.Выполнить(Массив[Счетчик]));
    КонецЦикла;

КонецПроцедуры
// ПотребительМоейКласснойБиблиотеки.os

Массив = Новый Массив();
Массив.Добавить(1);
Массив.Добавить(2);
Массив.Добавить(3);

Заменить(Массив, "Элемент -> Элемент + 1");

Сообщить(Массив[0]);
Сообщить(Массив[1]);
Сообщить(Массив[2]);

Результат:

// 2
// 3
// 4

Контекст

Лямбда-выражению можно установить Контекст, это позволит использовать поля контекста прямо в выражении, контекстом может выступать только структура

Например:

// МояКласснаяБиблиотека.os

Процедура СделайДело(ЧтоСделать) Экспорт

    ДелоПервое = Новый Структура("Состояние", "НеСделано");
    ДелоВторое = Новый Структура("Состояние", "НеСделано");

    Контекст = Новый Структура(
        "ДелоПервое, ДелоВторое",
        ДелоПервое,
        ДелоВторое
    );

    Делатель = Лямбда.Выражение(ЧтоСделать)
        .Контекст(Контекст)
        .ВДействие();

    Делатель.Выполнить(1);

    Сообщить("ДелоПервое = " + ДелоПервое.Состояние);
    Сообщить("ДелоВторое = " + ДелоВторое.Состояние);

КонецПроцедуры

Вызов метода:

// ПотребительМоейКласснойБиблиотеки.os

    МояКласснаяБиблиотека.СделайДело("(НомерДела) -> 
    |	Если НомерДела = 1 Тогда
    |		ДелоПервое.Состояние = ""Сделано""
    |	ИначеЕсли НомерДела = 2 Тогда
    |		ДелоВторое.Состояние = ""Сделано""
    |	КонецЕсли;"
    );

Результат:

ДелоПервое = Сделано
ДелоВторое = НеСделано

Как мы видим, поля контекста доступны в лямбда выражении по именам ключей структуры контекста

Захват объекта

В лямбда выражение можно захватить какой-то объект, чтобы в тексте лямбда выражения можно было использовать публичные и приватные поля объекта, а также публичные методы

Например:

// МояКласснаяБиблиотека.os

Функция Единичка(Алгоритм, Объект) Экспорт

    Действие = Лямбда.Выражение(Алгоритм)
        .ЗахватитьОбъект(Объект)
        .ВДействие();

    Возврат Действие.Выполнить(1);

КонецФункции

Вызов метода:

// ПотребительМоейКласснойБиблиотеки.os

Перем Двойка;
Перем Тройка Экспорт;

Функция Четверка() Экспорт
    Возврат 4;
КонецФункции

Результат = МояКласснаяБиблиотека.Единичка(
    "(Единица) -> Возврат Единица + Двойка + Тройка + Четверка()",
    ЭтотОбъект
);

// Результат = 10

Как мы видим, в выражении возможно обратиться к полям и методам переданного объекта

Аннотации

Есть возможность указать Аннотации как для параметров метода так и для самого метода, создаваемого из лямбда-выражения, например:

"&АннотацияМетода (Первый, Второй) -> Возврат Первый + Второй"

Будет преобразовано в:

&АннотацияМетода
Функция Принять(Первый, Второй)
    Возврат Первый + Второй;
КонецФункции

Так же и для параметров:

"(&АннотацияПараметра(1) Первый, &АннотацияПараметра(2) Второй) -> Возврат Первый + Второй"

Будет преобразовано в:

Функция Принять(&АннотацияПараметра(1) Первый, &АннотацияПараметра(2) Второй)
    Возврат Первый + Второй;
КонецФункции

Важно
При использовании аннотаций требуется использовать полную форму указания параметров т.е. со скобками (Параметр1, Параметр2).
В такой форме аннотации, оставшиеся за скобками параметров, будут принадлежать методу, а внутри скобок - параметрам, перед которым они идут.
Так же блок параметров должен быть отделён пробелом от самой аннотации, в ином случае они будут прочитаны как параметры аннотации:

&Аннотация (Парам1, Парам2) // <- Метод с двумя параметрами и аннотацией

&Аннотация(Парам1, Парам2) // <- Метод без параметров с аннотацией с двумя параметрами

Программный интерфейс

Лямбда

Выражение

// Создаёт лямбда-выражение из переданного выражения
//
// Параметры:
//   Выражение - Строка - Выражение, из которого будет создано лямбда-выражение
//
//  Возвращаемое значение:
//   ЛямбдаВыражение - Созданное лямбда-выражение
//
Функция Выражение(Выражение) 

ЛямбдаВыражение

ПриСозданииОбъекта

Процедура ПриСозданииОбъекта(Выражение) 

Интерфейс

// Устанавливает функциональный интерфейс для лямбда выражения.
//  В случае если метод интерфейса это функция:
//   1. Добавляет "Возврат" в лямбда выражение если оно однострочное и не содержит возврат
//   2. Проверяет что многострочное выражение содержит возврат значения
//  В случае В случае если метод интерфейса это процедура:
//   1. Проверяет что выражение не содержит возврат значения
//
// Параметры:
//   Интерфейс - ИнтерфейсОбъекта - Устанавливаемый функциональный интерфейс
//
//  Возвращаемое значение:
//   ЛямбдаВыражение - Инстанс текущего выражения
//
Функция Интерфейс(Интерфейс) 

Контекст

// Устанавливает контекст для лямбда выражения.
// При исполнении лямбда выражения все значения контекста будут доступны для использования в лямбда выражении
//
// Параметры:
//   Контекст - Структура - Устанавливаемый контекст
//
//  Возвращаемое значение:
//   ЛямбдаВыражение - Инстанс текущего выражения
//
Функция Контекст(Контекст) 

ЗахватитьОбъект

// Захватывает переданный объект для использования его в качестве контекста лямбда выражения.
// При исполнении лямбда выражения в нём будут доступны публичные и приватные поля переданного объекта
//  а так же публичные методы.
//
// Параметры:
//   Объект - Сценарий - Захватываемый объект
//
//  Возвращаемое значение:
//   ЛямбдаВыражение - Инстанс текущего выражения
//
Функция ЗахватитьОбъект(Объект) 

ВДействие

// Возвращает действие (делегат) на метод созданный по лямбда выражению
//
//  Возвращаемое значение:
//   Действие - Действие на метод лямбда выражения
//
Функция ВДействие() 

ВОбъект

// Возвращает сценарий созданный по лямбда выражению, который содержит метод согласно интерфейса
//
//  Возвращаемое значение:
//   Сценарий - Созданный сценарий
//
Функция ВОбъект() 

ФункциональныеИнтерфейсы

Вызываемый

// Возвращает интерфейс объекта содержащий функцию без параметров
//
//  Возвращаемое значение:
//   ИнтерфейсОбъекта - Искомый интерфейс
//
Функция Вызываемый() Экспорт

УниФункция

// Возвращает интерфейс объекта содержащий функцию с одним параметром
//
//  Возвращаемое значение:
//   ИнтерфейсОбъекта - Искомый интерфейс
//
Функция УниФункция() 

БиФункция

// Возвращает интерфейс объекта содержащий функцию с двумя параметрами
//
//  Возвращаемое значение:
//   ИнтерфейсОбъекта - Искомый интерфейс
//
Функция БиФункция() 

ТриФункция

// Возвращает интерфейс объекта содержащий функцию с тремя параметрами
//
//  Возвращаемое значение:
//   ИнтерфейсОбъекта - Искомый интерфейс
//
Функция ТриФункция() 

Запускаемый

// Возвращает интерфейс объекта содержащий процедуру без параметров
//
//  Возвращаемое значение:
//   ИнтерфейсОбъекта - Искомый интерфейс
//
Функция Запускаемый() Экспорт

УниПроцедура

// Возвращает интерфейс объекта содержащий процедуру с одним параметром
//
//  Возвращаемое значение:
//   ИнтерфейсОбъекта - Искомый интерфейс
//
Функция УниПроцедура() 

БиПроцедура

// Возвращает интерфейс объекта содержащий процедуру с двумя параметрами
//
//  Возвращаемое значение:
//   ИнтерфейсОбъекта - Искомый интерфейс
//
Функция БиПроцедура() 

ТриПроцедура

// Возвращает интерфейс объекта содержащий процедуру с тремя параметрами
//
//  Возвращаемое значение:
//   ИнтерфейсОбъекта - Искомый интерфейс
//
Функция ТриПроцедура() 

About

API для реализации функциональных интерфейсов для OneScript

Resources

License

Stars

Watchers

Forks

Packages