【Scala】getOrElse()でSomeのときに処理を続けたい

パターン1(前座)

まあ普通にできるよねってやつ。
今回とりあげたいパターンではないやつ。
* get -> String型
* else -> String型

// 値がSomeの場合
val strOp: Option[String] = Option("hello")
println(strOp.getOrElse("").length) // Int = 5

// 値がNoneの場合
val strOp2: Option[String] = None
println(strOp2.getOrElse("").length) // Int = 0

パターン2(本題)

slickとか、Option型の中身が構造体の場合、getOrElseではうまく行かないことがある。

例えば、下のようなcase classがOption型の時です。

private case class Sample(num: Int)

// Someの場合
val some: Option[Sample] = Option(new Sample(12))
// Noneの場合
val none: Option[Sample] = None

このようなことは多いです。
SlickのようなDb検索の場合は、検索結果を構造体で返しますが、ない場合にはNoneで返してくれます。

では、このOptionに対して
Someの場合はSample.numの値を返し、
Noneの場合は0を返す処理を書いてみます。

val result: Int = some.getOrElse(0).num

これはコンパイルエラーになります。
この場合、someの場合はSample型が返るので、Sample.numは12となりますが、
Noneの場合はelse(0)で即Int型が返るのでその後の0.numでエラーとなります。

fold()を使う

そんなときはfold()を使えば大丈夫!☆

val result: Int = some.fold(0)(samp => samp.num)

カリー化された関数ですね。(よくわかってない)
1つ目の引数にはNoneの時の返り値を。
2つ目の引数には、Someの時の返り値を入れます。

2つ目の方には、Someの時の値を受け取ることができるので、
(samp => samp.num)のように一度値を受け取ったあとに適切な値を返すことができます。