Функциональный тип — это тип, значениями которого являются методы. Функциональные типы позволяют хранить методы в переменных, передавать их в другие методы как аргументы и возвращать как результат.
Имя функционального типа содержит типы параметров и возвращаемого значения, разделенные символом лямбда-операции ->.
Например, иниц иализация и присваивание значения для функционального типа, значением которого является метод, принимающий два параметра типа Число и возвращающий значение типа Строка, может выглядеть следующим образом:
пер СуммаВСтроку: (Число, Число)->Строка = (А, Б) -> (А + Б).ВСтроку()
Значение функциональному типу может быть присвоено двумя способами:
Имя типа
Имя функционального типа содержит типы параметров и возвращаемого значения, разделенные символом лямбда-операции ->. Например:
-
Значением типа является метод с одним параметром типа Число, возвращающий значение типа Число:
знч Квадрат: (Число)->Число = (Число) -> Число * Число
-
Значением типа является метод с двумя параметрами типа Число, возвращающий значение типа Булево:
знч Равенство: (Число, Число)->Булево = (А, Б) -> А == Б
-
Значением типа является метод с двумя параметрами типа Число, возвращающий значение составного типа (Строка или Неопределено):
знч ДелениеВСтроку: (Число, Число)->Строка? = (А, Б) -> Б == 0 ? Неопределено : (А / Б).ВСтроку()
-
Значением типа является метод с одним параметром составного типа (Число или Неопределено), возвращающий значение составного типа (Строка или Число):
знч КвадратИлиНеопределено: (Число?)->Строка|Число = (Ч) -> (Ч == Неопределено ? "Не определено" : Ч * Ч)
-
Значением типа является метод без параметров, возвращающий значение типа Строка:
знч Приветствие: ()->Строка = () -> "Привет, Мир!"
-
Значением типа является метод с одним параметром типа Строка, не возвращающий ничего:
знч ДобавитьВМассив: (Строка)->ничто = (Строка) -> Массив.Добавить(Строка)
- Тип
ничто нельзя присвоить и с ним никак нельзя взаимодействовать.
- Значение типа
(XXX)->YYY можно присвоить в переменную типа (XXX)->ничто.
-
Составной тип, значением которого является либо Неопределено, либо метод с одним параметром типа Число, возвращающий значение типа Строка:
пер ОбработчикДоступен: Булево = Истина
знч ОбработчикЧисел: ((Число)->Строка)? = ОбработчикДоступен ? (Число) -> "Обработано: ${(Число * 3).ВСтроку()}" : Неопределено
-
Составной тип, значением которого является либо Булево, либо метод с одним параметром типа Число, возвращающий значение типа Строка:
пер РежимАктивен = Истина
знч ПреобразовательИлиОшибка: ((Число)->Строка)|Булево = РежимАктивен ? (Число) -> "[${Число.ВСтроку()}]" : Ложь
Если функциональный тип входит в составной тип, то имя такого функционального типа должно быть заключено в скобки, иначе все, что следует за лямбда-операцией ->, будет считаться составным типом результата.
-
При вызове составного функционального типа необходимо проверять его тип перед выполнением кода, чтобы избежать ошибок компиляции:
Правильно
метод Преобразователь(РежимАктивен: Булево): Булево|Строка|((Число)->Строка)
знч ПреобразовательИлиОшибка: ((Число)->Строка)|Булево = РежимАктивен ? (Число) -> "[${Число.ВСтроку()}]" : Ложь
если (ПреобразовательИлиОшибка).Получ итьТип() != Тип<Булево>
пер Функция = (ПреобразовательИлиОшибка как (Число)->Строка)
возврат Функция(10)
иначе
возврат ПреобразовательИлиОшибка
;
;
Неправильно
метод Преобразователь(): Булево|Строка|((Число)->Строка)
пер РежимАктивен = Истина
знч ПреобразовательИлиОшибка: ((Число)->Строка)|Булево = РежимАктивен ? (Число) -> "[${Число.ВСтроку()}]" : Ложь
если ПреобразовательИлиОшибка это (Число)->Строка
возврат ПреобразовательИлиОшибка(10)
иначе
возврат ПреобразовательИлиОшибка
;
;
-
Если в качестве типа переменной указано неизвестно, то проверка типов компилятора отключается и такое значение можно вызывать с любым количеством и типом параметров. Будет ошибка или нет, станет ясно только во время выполнения кода:
пер ЛюбойМетод: неизвестно
ЛюбойМетод = (Текст: Строка) -> Текст.ВВерхнийРегистр()
попытка
пер Результат1 = ЛюбойМетод("пример")
поймать Иск: Исключение
;
попытка
пер Результат2 = ЛюбойМетод(42)
поймать Искл: Исключение
;
В общем виде имя функционального типа выглядит следующим образом:
(тип-параметра-1, ..., тип-параметра-n)->тип-результата
Где:
- тип-параметра-1, ..., тип-параметра-N — типы параметров, если они есть;
-> — лямбда-операция;
- тип-результата — тип возвращаемого значения.
Вызов значения функционального типа
Синтаксически выглядит как вызов обычного метода:
[выражение.]имя([аргументы])
Например:
пер ФильтрЧисел: (Число)->Булево = (Ч) -> Ч > 0
пер Результат = ФильтрЧисел(-5)
пер ФорматироватьДату: (Дата)->Строка = (Д) -> Д.Представление("dd.MM.yyyy")
пер Результат = ФорматироватьДату(Дата.Сейчас())
При этом действует следующий приоритет разрешения имен:
- если существует метод с указанным именем (любого приоритета), то считается, что это вызов метода;
- иначе ищется свойство с указанным именем в порядке приоритетов и считается вызовом функционального типа.
Иерархия типов и вариантность
Значения функциональных типов обеспечивают ковариантность по возвращаемым типам и контравариантность по типам параметров.
Ковариантность по возвращаемым типам