Неизменяемые значения

В чистом функциональном программировании используются только неизменяемые значения. В Scala это означает:

Использование только неизменяемых переменных поднимает интересный вопрос: если все статично, как вообще что-то меняется?

Когда дело доходит до использования коллекций, один из ответов заключается в том, что существующая коллекция не меняется; вместо этого функция применяется к коллекции, чтобы создать новую. Именно здесь вступают в действие функции высшего порядка, такие как map и filter.

Например, представим, что есть список имен в нижнем регистре — List[String], и необходимо найти все имена, начинающиеся с буквы "j", чтобы затем сделать первые буквы заглавными. В ФП код будет выглядеть так:

val a = List("jane", "jon", "mary", "joe")
// a: List[String] = List("jane", "jon", "mary", "joe")
val b = a.filter(_.startsWith("j")).map(_.capitalize)
// b: List[String] = List("Jane", "Jon", "Joe")

Как показано, исходный список a не меняется. Вместо этого к a применяется функция фильтрации и преобразования, чтобы создать новую коллекцию, и результат присваивается неизменяемой переменной b.

Точно так же в ФП не используются классы с изменяемыми параметрами конструктора var. В ФП создание такого класса не привествуется:

class Person(var firstName: String, var lastName: String)

Вместо этого обычно создаются case class-ы, чьи параметры конструктора по умолчанию неизменяемые (val):

case class Person(firstName: String, lastName: String)

Теперь можно создать экземпляр Person как поле val:

val reginald = Person("Reginald", "Dwight")
// reginald: Person = Person(firstName = "Reginald", lastName = "Dwight")

Затем, при необходимости внести изменения в данные, используется метод copy, который поставляется с case class-ом, чтобы "обновлять данные через создание копии", например:

val elton = reginald.copy(
  firstName = "Elton",   
  lastName = "John"      
)
// elton: Person = Person(firstName = "Elton", lastName = "John")

Существуют множество других приёмов работы с неизменяемыми коллекциями и переменными.

В зависимости от задач вместо case class-ов можно создавать enum-ы, trait-ы или классы. Для более подробной информации См. главу "Моделирование данных".

Ссылки: