背景
scalaの勉強をしていく中で、mapはよく使うメソッドだと思います。自分もJSをずっとやっていたので配列をみるととりあえずmapかああとなります。
scalaにはOption型というものがあり、それにもmapを使うことができてflatMapとの違いが面白いなあと思ったので簡単にまとめます。
map
簡単に書きます。
val msgOpt: Option[String] = Some("a")
val mappedMsgOpt = msgOpt.map(msg => msg)
println(mappedMsgOpt) // Some("a")
Option型に対してmapをして、値を返すだけです。
ここで言いたいことはmap は文脈を保ったまま、ふつうの値を取ってふつうの値を返す関数を適用するということです。
そして最終的にはOptionに包まれて返ってきます。
flatMap
ここも簡単に書きます。
val msgOpt: Option[String] = Some("a")
val flatMappedMsgOpt = msgOpt.flatMap(msg => Some(msg))
println(flatMappedMsgOpt) // Some("a")
結果としては同じですが、flatMapの中の関数がmapとは違います。
flatMapは必ず文脈を保ったまま計算をするということです。
flatMapの中の関数は文脈を保ってなければいけません。
val flatMappedMsgOpt = msgOpt.flatMap(msg => msg) // エラー
こう書いてしますとStringが返ってくるため、Optionという文脈が保たれたいのでエラーになります。
Optionという文脈さえ保たれていれば、対象が変わっても問題ないのがflatMapの特徴です。
val flatMappedMsgOpt = msgOpt.flatMap(msg => Some(1))
意味のないことをしていますが、Stringで受け取ってIntで返すといったこともできます。
両者共通
mapとflatMapに共通するものとして、Noneを受け取った場合があります。
val msgOpt: Option[String] = None
val flatMappedMsgOpt = msgOpt.flatMap(msg => Some(1))
println(flatMappedMsgOpt) // None
val mappedMsgOpt = msgOpt.map(msg => msg)
println(mappedMsgOpt) // None
Noneだった場合は処理が行われずスキップされNoneが返されます。
まとめ
mapとflatMapの違いについて整理することができました。
Option型をうまく扱えるようになりたいですね。