Примеры использования функциональных типов
Хранение метода в переменной
Значение функционального типа можно присвоить переменной и использовать его в дальнейшем. Например, это может быть лямбда-выражение, вычисляющее длину строки:
метод ВычислитьДлину()
знч МетодДлина = (СтрокаТекста: Строка) -> СтрокаТекста.Длина()
пер ДлинаСтроки = МетодДлина("Моя строка")
;
Также это может быть ссылка на метод, в данном случае на метод ПолучитьДлину():
метод ПолучитьДлину(СтрокаТекста: Строка): Число
возврат СтрокаТекста.Длина()
;
метод ВычислитьДлину()
знч МетодДлина = &ПолучитьДлину
пер ДлинаСтроки = МетодДлина("Моя строка")
;
Ссылка на системный метод
Вы можете ссылаться не только на собственные методы, но и на системные. Например, можно сослаться на метод Строка.Длина():
метод ВычислитьДлину()
знч МетодДлина = &Строка.Длина
пер ДлинаСтроки = МетодДлина("Моя строка")
;
Вызов системного метода с параметром функционального типа
Некоторые системные методы имеют параметры функционального типа.
Например, в первый параметр метода Массив<тип-элемента>.СортироватьПо() требуется передать выражение, возвращающее то свойство элемента массива, по которому массив нужно отсортировать.
Пример использования этого метода выглядит следующим образом. Массив студентов, каждый из которых представлен структурой Студент, сортируется по полю Оценка этой структуры в порядке возрастания его значения:
структура Студент
знч Фамилия: Строка
знч Оценка: Число
;
метод Сортировать(): Массив<Студент>
знч МассивСтудентов = [новый Студент("Иванов", 5),
новый Студент("Савинская", 4),
новый Студент("Сидорова", 5),
новый Студент("Булатов", 3),
новый Студент("Кузнецова", 5)]
возврат МассивСтудентов.СортироватьПо(ПарСтудент -> ПарСтудент.Оценка)
;
Передача метода в другой метод
В следующих примерах в метод в качестве аргументов передаются две строки (ПерваяСтрока, ВтораяСтрока), которые нужно сравнить между собой. Для этого вызывается метод СравнитьСтроки(), в котором описан алгоритм сравнения:
метод Пример(ПерваяСтрока: Строка, ВтораяСтрока: Строка)
пер Результат = СравнитьСтроки(ПерваяСтрока, ВтораяСтрока)
;
метод СравнитьСтроки(Первая: Строка, Вторая: Строка): Булево
возврат Первая.Длина() < Вторая.Длина()
;
Использование лямбда-выражения
Предположим, нужно использовать разные алгоритмы сравнения, а не один и тот же. Тогда можно в метод СравнитьСтроки() добавить третий параметр функционального типа, в который передавать тот алгоритм сравнения, который нужен в данный момент:
метод Пример(ПерваяСтрока: Строка, ВтораяСтрока: Строка)
пер Результат = СравнитьСтроки(
ПерваяСтрока,
ВтораяСтрока,
(Строка1, Строка2) -> Строка1.Длина() < Строка2.Длина()
)
;
метод СравнитьСтроки(
Первая: Строка,
Вторая: Строка,
Сравнить: (Строка, Строка)->Булево
): Булево
возврат Сравнить(Первая, Вторая)
;
В примере выше в вызове метода СравнитьСтроки() записано лямбда-выражение:
(Строка1, Строка2) -> Строка1.Длина() < Строка2.Длина()
Оно означает, что передается метод с двумя параметрами, который сравнивает длину первого параметра с длиной второго параметра операцией «меньше» <.
В объявлении метода СравнитьСтроки() указано, что его третий параметр имеет функциональный тип:
Сравнить: (Строка, Строка)->Булево
Имя этого параметра — Сравнить, в него будет передан метод, который принимает два аргумента типа Строка и возвращает значение типа Булево.
В теле метода СравнитьСтроки() записан вызов значения функционального типа:
Таким образом вызывается метод, переданный в третьем параметре Сравнить. Он получает две строки, которые были переданы в метод первым и вторым аргументами.
Использование ссылки на метод
Вместо лямбда-выражений можно использовать ссылки на существующие методы. Например, если алгоритм сравнения уже описан в методе СравнитьНаМеньше(), то вместо лямбда-выражения можно использовать ссылку на этот метод:
метод Пример(ПерваяСтрока: Строка, ВтораяСтрока: Строка)
пер Результат = СравнитьСтроки(ПерваяСтрока,
ВтораяСтрока,
&СравнитьНаМеньше)
;
метод СравнитьНаМеньше(Первая: Строка, Вторая: Строка): Булево
возврат Первая.Длина() < Вторая.Длина()
;
метод СравнитьСтроки(
Первая: Строка,
Вторая: Строка,
Сравнить: (Строка, Строка)->Булево): Булево
возврат Сравнить(Первая, Вторая)
;
Чтобы написать ссылку на метод, перед именем метода нужно поставить амперсанд & (подробнее).
Практический пример
Рассмотрим реализацию описанных выше алгоритмов на практическом примере.
Существует список студентов, который нужно отфильтровать по вводимой пользователем оценке. Например, показать только отличников.
Каждый студент описывается экземпляром структуры Студент, у которой есть два поля: Фамилия и Оценка. Для хранения списка студентов используется массив Массив<Студент>. Список студентов выглядит следующим образом:
| Фамилия | Оценка |
|---|
| Иванов | 5 |
| Савинская | 4 |
| Сидорова | 5 |
| Булатов | 3 |
| Кузнецова | 5 |
Список студентов формируется в отдельном методе ПолучитьМассив():
метод ПолучитьМассив(): Массив<Студент>
возврат [новый Студент("Иванов", 5),
новый Студент("Савинская", 4),
новый Студент("Сидорова", 5),
новый Студент("Булатов", 3),
новый Студент("Кузнецова", 5)]
;
Фильтрация обычным способом
Создайте метод фильтрации, который получает на входе массив студентов и оценку для фильтрации, сравнивает оценку каждого студента с введенной оценкой и возвращает полученный список студентов:
метод Фильтровать(Студенты: Массив<Студент>, Оценка: Число): Массив<Строка>
пер СписокСтудентов: Массив<Строка>
для Студент из Студенты
если Студент.Оценка == Оценка
СписокСтудентов.Добавить(Студент.Фамилия)
;
;
возврат СписокСтудентов
;
Оценка, введенная пользователем, передается как аргумент в метод Пример(), в котором вызывается метод Фильтровать(), куда передается исходный список студентов и оценка:
метод Пример(Оценка: Число): Массив<Строка>
пер Студенты = ПолучитьМассив()
пер ОтфильтрованныйСписок = Фильтровать(Студенты, Оценка)
возврат ОтфильтрованныйСписок
;
Полный пример
структура Студент
знч Фамилия: Строка
знч Оценка: Число
;
метод ПолучитьМассив(): Массив<Студент>
возврат [новый Студент("Иванов", 5),
новый Студент("Савинская", 4),
новый Студент("Сидорова", 5),
новый Студент("Булатов", 3),
новый Студент("Кузнецова", 5)]
;
метод Фильтровать(Студенты: Массив<Студент>, Оценка: Число): Массив<Строка>
пер СписокСтудентов: Массив<Строка>
для Студент из Студенты
если Студент.Оценка == Оценка
СписокСтудентов.Добавить(Студент.Фамилия)
;
;
возврат СписокСтудентов
;
метод Пример(Оценка: Число): Массив<Строка>
пер Студенты = ПолучитьМассив()
пер ОтфильтрованныйСписок = Фильтровать(Студенты, Оценка)
возврат ОтфильтрованныйСписок
;
При вводе оценки 5 вы получите следующий результат:
Метод Фильтровать() всегда использует только одно выражение фильтрации — сравнение на равенство. Но что если нужно каждый раз использовать новое выражение для фильтрации? Для этого можно использовать лямбда-выражение, которое позволит каждый ра з передавать в виде аргумента новое выражение фильтрации.
Использование лямбда-выражения
Измените метод Фильтровать(), добавив ему третий параметр УдовлетворяетУсловию. Это будет параметр функционального типа, который будет принимать метод, описанный лямбда-выражением. В теле метода Фильтровать() этот метод будет принимать два других аргумента — студента и оценку:
метод Фильтровать(Студенты: Массив<Студент>,
Оценка: Число,
УдовлетворяетУсловию: (Студент, Число)->Булево): Массив<Строка>
пер СписокСтудентов: Массив<Строка>
для Студент из Студенты
если УдовлетворяетУсловию(Студент,Оценка)
СписокСтудентов.Добавить(Студент.Фамилия)
;
;
возврат СписокСтудентов
;
Чтобы передать в метод Фильтровать() лямбда-выражение, доработайте его вызов:
метод Пример(Оценка: Число)
пер Студенты = ПолучитьМассив()
Фильтровать(Студенты,
Оценка,
(ПарСтудент, ПарОценка) -> ПарСтудент.Оценка == ПарОценка)
;
Полный пример
структура Студент
знч Фамилия: Строка
знч Оценка: Число
;
метод ПолучитьМассив(): Массив<Студент>
возврат [новый Студент("Иванов", 5),
новый Студент("Савинская", 4),
новый Студент("Сидорова", 5),
нов ый Студент("Булатов", 3),
новый Студент("Кузнецова", 5)]
;
метод Фильтровать(Студенты: Массив<Студент>,
Оценка: Число,
УдовлетворяетУсловию: (Студент, Число)->Булево): Массив<Строка>
пер СписокСтудентов: Массив<Строка>
для Студент из Студенты
если УдовлетворяетУсловию(Студент,Оценка)
СписокСтудентов.Добавить(Студент.Фамилия)
;
;
возврат СписокСтудентов
;
метод Пример(Оценка: Число): Массив<Строка>
пер Студенты = ПолучитьМассив()
пер ОтфильтрованныйСписок = Фильтровать(Студенты,
Оценка,
(ПарСтудент, ПарОценка) -> ПарСтудент.Оценка == ПарОценка)
возврат ОтфильтрованныйСписок
;
При вводе оценки 5 вы получите тот же результат: [Иванов, Сидорова, Кузнецова]
Таким образом, в виде переменной функционального типа можно «снаружи» передать в метод любое выражение фильтрации.
Использование ссылки на метод
Как поступить в том случае, если метод, содержащий выражение фильтрации, уже существует? Например, он называется ИмеетОценку():
метод ИмеетОценку(Студент: Студент, Оценка: Число): Булево
возврат Студент.Оценка == Оценка
;
Этот метод имеет два параметра типа Студент и Число и возвращает значение типа Булево, то есть соответствует функциональному типу, указанному для параметра УдовлетворяетУсловию:
УдовлетворяетУсловию: ((Студент, Число)->Булево)
Передайте метод ИмеетОценку() с помощью ссылки:
метод Пример(Оценка: Число)
пер Студенты = ПолучитьМассив()
Фильтровать(Студенты, Оценка, &ИмеетОценку)
;
Полный пример
структура Студент
знч Фамилия: Строка
знч Оценка: Число
;
метод ПолучитьМассив(): Массив<Студент>
возврат [новый Студент("Иванов", 5),
новый Студент("Савинская", 4),
новый Студент("Сидорова", 5),
новый Студент("Булатов", 3),
новый Студент("Кузнецова", 5)]
;
метод Фильтровать(Студенты: Массив<Студент>,
Оценка: Число,
УдовлетворяетУсловию: (Студент, Число)->Булево): Массив<Строка>
пер СписокСтудентов: Массив<Строка>
для Студент из Студенты
если УдовлетворяетУсловию(Студент,Оценка)
СписокСтудентов.Добавить(Студент.Фамилия)
;
;
возврат СписокСтудентов
;
метод ИмеетОценку(Студент: Студент, Оценка: Число): Булево
возврат Студент.Оценка == Оценка
;
метод Пример(Оценка: Число):Массив<Строка>
пер Студенты = ПолучитьМассив()
пер ОтфильтрованныйСписок = Фильтровать(Студенты, Оценка, &ИмеетОценку)
возврат ОтфильтрованныйСписок
;
При вводе оценки 5 вы получите тот же результат: [Иванов, Сидорова, Кузнецова]
См. также