Почему мы используем flatten? Чем он отличается от flatMap? - PullRequest
0 голосов
/ 30 октября 2018

В скале, почему мы используем flatten? Чем он отличается от flatMap? Примеры, которые включают Фьючерсы, были бы очень полезны.

1 Ответ

0 голосов
/ 30 октября 2018

flatten не включает в себя часть "карты" flatMap. Думайте об этом как о просто сглаживании вложенных структур. Option[Option[Int]] становится просто Option[Int] или List[List[Int]] становится List[Int] (путем объединения элементов отдельных списков).

Напротив, отображение изменяет элементы, содержащиеся в структурах. Итак

Some(4).map(_ + 1) // evaluates to Some(5)

Иногда функция, переданная в map, возвращает экземпляр самой базовой структуры. Допустим, у вас есть необязательный идентификатор, и если он установлен, вы хотите просмотреть его в базе данных, не зная, присутствует ли запись, поэтому ваша функция также возвращает Option:

val optionalId: Option[String] = ???
def getRecord(id: String): Option[Record] = ???

val naiveResult: Option[Option[Record]] = optionalId.map(getRecord)

Обычно это не то, что вы хотите. По сути, у вас есть Option[Record], и дополнительное вложение не требуется. Так что вы бы позвонили flatten сразу после map:

optionalId.map(getRecord).flatten // evaluates to an Option[Record]

Теперь flatMap по сути является комбинацией обоих в одном методе:

optionalId.flatMap(getRecord) // also yields an Option[Record]

Применение flatMap не ограничивается коллекциями, но гораздо более общим. Другой пример, где это пригодится, это фьючерсы. Допустим, у нас нет необязательного идентификатора, но есть Future [String], который представляет вычисление, которое в конечном итоге даст идентификатор. У нас также есть метод, который дает нам Future[Record] для идентификатора. Теперь мы можем получить Future[Record] из Future[String] следующим образом:

val idFuture: Future[String] = ???
def getRecord(id: String): Future[Record] = ???

val recordFuture: Future[Record] = idFuture.flatMap(getRecord)
...