Screaming Loud

日々是精進

ScalaにおけるSeq, Option, Futureとmap,flatMap の扱い

Scalaにおける一つ目の関門は、forやmapを使ってOption型を操作することだと思います。

そこで、forやOptionやFutureを理解しやすいようなイメージを共有したいと思います。

Scalaでのmap

Scalaの型でのラッピングは同じ扱い」
これは何かというと、SeqであったりOptionであったりFutureであっても、

val a = Seq(1)
val b = Option(1)
val c = Future {1}

というように同じ1を包むことができます。

一番最初にmapを理解するのは、Seqでの利用法だと思いますが、
mapの操作についてもう一度おさらいしてみると、
「中身の要素を順番に書き換えていく」
という操作です。

例えば、以下のように配列の中身に対して1ずつ足すという操作です。

Seq(1,2,3).map(a => a + 1)
# Seq(2,3,4)

これって、実はOptionでもFutureでも同じことなのです。
Seqはリストだけど、Optionは違うじゃんみたいなことは思わず、同じように型でラッピングされているんだとかんがえると、以下のようにOptionの中身に対して1を足すという操作だとわかります。

Option(2).map(o => o + 1)
# Option(3)

Futureに関しても同じです。

Future {1}.map(f => f + 1)
# Future {2}

Futureの場合、こうすることで、非同期処理を止めずに処理をつなげることができるので、
効率のよい非同期処理を作成することができます。

Scalaでのforeach

上の操作に対して、値を返さないのがforeachです。
mapの値を返さないものなので、説明は割愛します。

ScalaでのflatMap

flatMapは、つぶしながら順番中の要素を操作して潰すというイメージです。

例えば、以下のようなものです。

val a = Seq(Seq(1), Seq(2,3))
a.flatMap(f => f)
# Seq(1,2,3)

型で説明すると、
Seq[Seq[A]] => Seq[A] *1
このような変換を行っています。

Seq[Option[A]]の場合、flatMapを使うことでSeq[A]に変換することができます。

Seq(Some(1), Some(2)).flatMap(a => a)
# Seq(1,2)


Futureの場合は、非同期処理に関して同期を取るという操作になります。
以下のようなFuture[Future[Int]]という型は、flatMapを介すことでFuture[Int]になります。

Future{Future{1}}.flatMap(a => a)

これは、内側のFuture(非同期処理)と外側のFuture(非同期処理)の同期を取ることで、非同期処理を止めるのではなく内側のFutureの処理と外側のFutureの処理の同期のみを取るということを行っています。
これにより、非同期処理の効率性が図られています。

flatMapに関しては、以下にも詳しく書いてあるのであわせて読んでみると良いと思います。
flatMapをマスターする - Qiita

*1:Aは適当な型です。コード例ではInt型を入れています。