背景
ある日、下記のコードがなぜ動くのか理解できなかった。
val a = Map(1 -> "one", 2 -> "two")
val b = Option(1)
val x = b.collect(a)
println(x) // Some("one")
そもそもなぜこんなことをしたのかは割愛。
collectの認識
collectはfilterとmapが混じったものという認識でした。
下記のようなコードの風に使うんだなと。
class Person(val name: String, val age: Int)
val a = Seq(new Person("a", 10), new Person("b", 20), new Person("c", 30))
// 下二つは同じ
val b = a.collect{case person if(person.age > 15) => person.name}
val c = a.filter(_.age > 15).map(_.name)
println(b) // Seq("b", "c")
println(c) // Seq("b", "c")
見えてなかった本質
本質は別にあって、collectは引数にpartialfunction
を受け取る関数なんだと!
partialfunctionとはなんぞやということなんやが、以下が簡単なpartialfunctionの例です。
partialfunctionを使うときは型宣言は省略することはできなくて省略すると怒られます。
val pf: PartialFunction[Int, String] = {case 5 => "五"}
val c = pf(5)
val d = pf(6)
println(c) // "五"
println(d) // match error
みたまんまで、マッチする場合のみ処理を行う関数のことを指します。だから部分関数
なんですね。
ここで本題に戻りますが、なんとMapはこのpartialfunctionをmixInしております。
val a = Map(1 -> "one", 2 -> "two")
val b = a(1)
println(b) // "one"
このMapからキーを与えて値をとるこの動きがまさに部分関数
な訳です。
それにあったキーのみ値を返す動きをするのがmixIn
している理由な訳ですね。
このようなことからMap自身がpartialfuncitonとなり、collectの引数に渡せるのだと。。scala面白え。
余談
MapでできるのであればSeqでも。。
val seq = Seq("zero", "one", "two")
val collected = Option(0).collect(seq)
println(collected) // Some("zero")
できた。面白い。