【Scala】Optionの使用方法の変遷について

私のOptionについての認識の変遷。たぶんみんなこんな道を歩むんじゃないかな?と思ったので、忘れないうちに書いておく。

レベル1:Optionはnull pointer exceptionを起こさないためのラッパーだ

[scala]
scala> val maybeInt = Option(3)
maybeInt: Option[Int] = Some(3)

scala> if(maybeInt.isDefined) maybeInt.get else 0
res2: Int = 3
[/scala]

ラッパーなのでとりあえずどういうメソッドを呼んでもヌルポにならないから安心だよね。戻り値が存在しないようなパターンがある関数ではOption[A]を戻り値の型にしておけば安心だよね。でもこれってnullチェックしてるのと大差ないような…。

レベル2:パターンマッチをつかえ

[scala]
scala> val maybeInt = Option(3)
maybeInt: Option[Int] = Some(3)

scala> maybeInt match {
| case None => 0
| case Some(x) => x + 2
| }
res3: Int = 5
[/scala]

パターンマッチて「ちょっと高機能なswitchなんでしょ?」とか思ってたけど、実際使ってみるとすげー便利。マジ激アツ。抽出子やcase classの使い方が分かってきてとにかくmatchを多用して嬉しがる時期。

レベル3:mapをつかえ

[scala]
scala> val maybeInt = Option(3)
maybeInt: Option[Int] = Some(3)

scala> maybeInt.map(_+2).getOrElse(0)
res4: Int = 5
[/scala]

モナドの概念がなんとなく分かってきて使えるようになる。え、なんでOptionにIntを直接加算できるの?なにこれ?から始まって、一通り使い方を理解してmapやflatMapを組み合わせることができるようになる。

レベル3.5:forをつかえ

[scala]
scala> val maybeFamilyName = Option("mitarai")
maybeFamilyName: Option[String] = Some(mitarai)

scala> val maybeFirstName = Option("benzo")
maybeFirstName: Option[String] = Some(benzo)

scala> val maybeAge = Option(36)
maybeAge: Option[Int] = Some(36)

scala> for{
| fa <- maybeFamilyName
| fi <- maybeFirstName
| a <- maybeAge
| } yield s"$fa $fi ($a)"
res1: Option[String] = Some(mitarai benzo (36))

[/scala]

match文がネストしていたような箇所も、「for使えばネスト減らせるじゃん!いいじゃん!forってモナドを便利に使うためのシンタックスシュガーだったのかー」と気づく。

レベル4以降:Scalazの世界へ

以降、勉強中のため謎。単にnullチェックとかだけならわざわざScalaz使ったところでそこまで便利になるわけではないのかな。