В чистом функциональном программировании используются только неизменяемые значения. В Scala это означает:
- все переменные создаются как поля
val
- используются только неизменяемые классы коллекций, такие как
List
,Vector
и неизменяемые классыMap
иSet
Использование только неизменяемых переменных поднимает интересный вопрос: если все статично, как вообще что-то меняется?
Когда дело доходит до использования коллекций, один из ответов заключается в том,
что существующая коллекция не меняется; вместо этого функция применяется к коллекции, чтобы создать новую.
Именно здесь вступают в действие функции высшего порядка, такие как map
и filter
.
Например, представим, что есть список имен в нижнем регистре — List[String]
,
и необходимо найти все имена, начинающиеся с буквы "j"
, чтобы затем сделать первые буквы заглавными.
В ФП код будет выглядеть так:
val a = List("jane", "jon", "mary", "joe")
val b = a.filter(_.startsWith("j"))
.map(_.capitalize)
Как показано, исходный список a
не меняется.
Вместо этого к a
применяется функция фильтрации и преобразования, чтобы создать новую коллекцию,
и результат присваивается неизменяемой переменной b
.
Точно так же в ФП не используются классы с изменяемыми параметрами конструктора var
.
В ФП создание такого класса не привествуется:
// не стоит этого делать в ФП
class Person(var firstName: String, var lastName: String)
--- ---
Вместо этого обычно создаются case
классы, чьи параметры конструктора по умолчанию неизменяемые (val
):
case class Person(firstName: String, lastName: String)
Теперь можно создать экземпляр Person
как поле val
:
val reginald = Person("Reginald", "Dwight")
Затем, при необходимости внести изменения в данные, используется метод copy
,
который поставляется с case
классом, чтобы “обновлять данные через создание копии”,
например так:
val elton = reginald.copy(
firstName = "Elton", // обновить имя
lastName = "John" // обновить фамилию
)
Существуют множество других приёмов работы с неизменяемыми коллекциями и переменными.
В зависимости от задач вместо
case
классов можно создавать перечисления, trait-ы или классы. Для более подробной информации см. главу “Моделирование данных”.
Contributors to this page:
Contents
- Введение
- Возможности Scala
- Почему Scala 3?
- Почувствуй Scala
- Пример 'Hello, World!'
- REPL
- Переменные и типы данных
- Структуры управления
- Моделирование данных
- Методы
- Функции первого класса
- Одноэлементные объекты
- Коллекции
- Контекстные абстракции
- Верхнеуровневые определения
- Обзор
- Первый взгляд на типы
- Интерполяция строк
- Структуры управления
- Моделирование предметной области
- Инструменты
- Моделирование ООП
- Моделирование ФП
- Методы
- Особенности методов
- Main методы в Scala 3
- Обзор
- Функции
- Анонимные функции
- Параметры функции
- Eta расширение
- Функции высшего порядка
- Собственный map
- Создание метода, возвращающего функцию
- Обзор
- Пакеты и импорт
- Коллекции в Scala
- Типы коллекций
- Методы в коллекциях
- Обзор
- Функциональное программирование
- Что такое функциональное программирование?
- Неизменяемые значения
- Чистые функции
- Функции — это значения
- Функциональная обработка ошибок
- Обзор
- Типы и система типов
- Определение типов
- Параметризованные типы
- Пересечение типов
- Объединение типов
- Алгебраические типы данных
- Вариантность
- Непрозрачные типы
- Структурные типы
- Зависимые типы функций
- Другие типы
- Контекстные абстракции
- Методы расширения
- Параметры контекста
- Контекстные границы
- Given импорты
- Классы типов
- Многостороннее равенство
- Неявное преобразование типов
- Обзор
- Параллелизм
- Scala утилиты
- Сборка и тестирование проектов Scala с помощью Sbt
- Рабочие листы
- Взаимодействие с Java