Хотя каждый когда-либо созданный язык программирования, вероятно, позволяет писать чистые функции,
вторая важная особенность ФП на Scala заключается в том, что функции можно создавать как значения,
точно так же, как создаются значения String
и Int
.
Эта особенность даёт много преимуществ, опишем наиболее распространенные из них: (a) можно определять методы, принимающие в качестве параметров функции и (b) можно передавать функции в качестве параметров в методы.
Такой подход можно было наблюдать в предыдущих главах, когда демонстрировались такие методы, как map
и filter
:
val nums = (1 to 10).toList
val doubles = nums.map(_ * 2) // удваивает каждое значение
val lessThanFive = nums.filter(_ < 5) // List(1,2,3,4)
В этих примерах анонимные функции передаются в map
и filter
.
Анонимные функции также известны как лямбды (lambdas).
Помимо передачи анонимных функций в filter
и map
, в них также можно передать методы:
// два метода
def double(i: Int): Int = i * 2
def underFive(i: Int): Boolean = i < 5
// передача этих методов в filter и map
val doubles = nums.filter(underFive).map(double)
Возможность обращаться с методами и функциями как со значениями — мощное свойство, предоставляемое языками функционального программирования.
Технически функция, которая принимает другую функцию в качестве входного параметра, известна как функция высшего порядка. (Если вам нравится юмор, как кто-то однажды написал, это все равно, что сказать, что класс, который принимает экземпляр другого класса в качестве параметра конструктора, является классом высшего порядка.)
Функции, анонимные функции и методы
В примерах выше анонимная функция это:
_ * 2
Как было показано в обсуждении функций высшего порядка, _ * 2
- сокращенная версия синтаксиса:
(i: Int) => i * 2
Такие функции называются “анонимными”, потому что им не присваивается определенное имя. Для того чтобы это имя задать, достаточно просто присвоить его переменной:
val double = (i: Int) => i * 2
Теперь появилась именованная функция, назначенная переменной double
.
Можно использовать эту функцию так же, как используется метод:
double(2) // 4
В большинстве случаев не имеет значения, является ли double
функцией или методом;
Scala позволяет обращаться с ними одинаково.
За кулисами технология Scala, которая позволяет обращаться с методами так же,
как с функциями, известна как Eta Expansion.
Эта способность беспрепятственно передавать функции в качестве переменных
является отличительной чертой функциональных языков программирования, таких как Scala.
И, как было видно на примерах map
и filter
,
возможность передавать функции в другие функции помогает создавать код,
который является кратким и при этом читабельным — выразительным.
Вот еще несколько примеров:
List("bob", "joe").map(_.toUpperCase) // List(BOB, JOE)
List("bob", "joe").map(_.capitalize) // List(Bob, Joe)
List("plum", "banana").map(_.length) // List(4, 6)
val fruits = List("apple", "pear")
fruits.map(_.toUpperCase) // List(APPLE, PEAR)
fruits.flatMap(_.toUpperCase) // List(A, P, P, L, E, P, E, A, R)
val nums = List(5, 1, 3, 11, 7)
nums.map(_ * 2) // List(10, 2, 6, 22, 14)
nums.filter(_ > 3) // List(5, 11, 7)
nums.takeWhile(_ < 6) // List(5, 1, 3)
nums.sortWith(_ < _) // List(1, 3, 5, 7, 11)
nums.sortWith(_ > _) // List(11, 7, 5, 3, 1)
nums.takeWhile(_ < 6).sortWith(_ < _) // List(1, 3, 5)
Contributors to this page:
Contents
- Введение
- Возможности Scala
- Почему Scala 3?
- Почувствуй Scala
- Пример 'Hello, World!'
- REPL
- Переменные и типы данных
- Структуры управления
- Моделирование данных
- Методы
- Функции первого класса
- Одноэлементные объекты
- Коллекции
- Контекстные абстракции
- Верхнеуровневые определения
- Обзор
- Первый взгляд на типы
- Интерполяция строк
- Структуры управления
- Моделирование предметной области
- Инструменты
- Моделирование ООП
- Моделирование ФП
- Методы
- Особенности методов
- Main методы в Scala 3
- Обзор
- Функции
- Анонимные функции
- Параметры функции
- Eta расширение
- Функции высшего порядка
- Собственный map
- Создание метода, возвращающего функцию
- Обзор
- Пакеты и импорт
- Коллекции в Scala
- Типы коллекций
- Методы в коллекциях
- Обзор
- Функциональное программирование
- Что такое функциональное программирование?
- Неизменяемые значения
- Чистые функции
- Функции — это значения
- Функциональная обработка ошибок
- Обзор
- Типы и система типов
- Определение типов
- Параметризованные типы
- Пересечение типов
- Объединение типов
- Алгебраические типы данных
- Вариантность
- Непрозрачные типы
- Структурные типы
- Зависимые типы функций
- Другие типы
- Контекстные абстракции
- Методы расширения
- Параметры контекста
- Контекстные границы
- Given импорты
- Классы типов
- Многостороннее равенство
- Неявное преобразование типов
- Обзор
- Параллелизм
- Scala утилиты
- Сборка и тестирование проектов Scala с помощью Sbt
- Рабочие листы
- Взаимодействие с Java