Скала: как избежать мутации?

Это обычное дело, когда нужно накапливать данные. То, как я привык к этому, - это добавление фрагментов данных в массив. Но это плохая практика в скале, так как я могу избежать этого?

3 ответа

Решение

Ну, есть два общих способа борьбы с накоплением: рекурсия и складывание. Давайте рассмотрим очень простые примеры каждого из них, чтобы вычислить сумму значений списка.

def sumRecursively(list: List[Int]): Int = {
  def recurse(list: List[Int], acc: Int): Int =
    if (list.isEmpty) acc
    else recurse(list.tail, acc + list.head)
  recurse(list, 0)
}

def sumFolding(list: List[Int]): Int =
  list.foldLeft(0){ case (acc, n) => acc + n }

Есть много вариантов этого, которые лучше обрабатывают тот или иной случай.

В большинстве случаев операции "map" и "flatMap" используются для функциональной генерации структур данных. Оба начинают с одной структуры данных, применяют некоторую операцию к каждому элементу в ней и возвращают новую структуру данных той же формы, что и оригинал. Они отличаются только тем, как заполняется новая структура данных. Эти два настолько распространены и настолько мощны, что в Scala есть специальный синтаксис - для понимания - для их поддержки. Внешнее понимание выглядит внешне похожим на цикл for в стиле Java, но фактически компилируется в серию вызовов map и flatMap (среди нескольких других).

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

Также стоит отметить, что "map" и "flatMap" на самом деле являются частными случаями другой, более мощной функции: "fold". "fold" (реализованный как "foldLeft" и "foldRight" по техническим причинам) может использоваться как для построения структур данных, так и для их разбивки.

На самом деле это не так. Вы можете использовать Vector в скале, которая является частью scala.collection.immutable пакет по умолчанию. Это создаст неизменную коллекцию, которая будет возвращать новый (другой) экземпляр каждый раз, когда вы добавляете его.

Дополнительная информация:

http://www.scala-lang.org/docu/files/collections-api/collections_15.html

Другие вопросы по тегам