Scalaでパターンマッチによる分解で、よく紹介されるのはListだと思います。
例えば、このような変数を定義して
val xs = List(1, 2, 3)
このようなパターンマッチを行います。
xs match { case 1 :: 2 :: 3 :: Nil => println("matched!!") case _ => // ここには来ない } xs match { case one :: rest => println(s"matched!! one[$one], rest[$rest]") case _ => // ここには来ない }
結果。
matched!! matched!! one[1], rest[List(2, 3)]
こんな感じのことを、Seqに対しても行うことのできる+:と:+の存在に今日気付きました。
知らなかったー!
*まあ、ListもSeqですが
Scala 2.10で追加されたものらしいです。
なお、これらはSeq(正確にはSeqLikeトレイトをMix-inしたもの)に対してパターンマッチをかけられるもののようですので、MapやArrayに対しては不可ですね。
+:
正確には、scala.collection.+:です。Seqをheadとtailに分解することができます。
ここは、Vectorを使って例を。
val v = Vector(1, 2, 3)
このようなパターンマッチのコードを用意します。
// headとtail v match { case 1 +: 2 +: rest => println(s"matched!! $rest") case _ => // ここには来ない } v match { case n +: rest => println(s"matched!! $n +: $rest") case _ => // ここには来ない }
結果。
matched!! Vector(3) matched!! 1 +: Vector(2, 3)
ちゃんとできてる!素晴らしい!
ListのNilのようなものはないと思いますが、一応最後の要素が空になってもマッチするみたいです。
v match { case 1 +: 2 +: 3 +: rest => println(s"matched! $rest") case _ => // ここには来ない }
結果。
matched! Vector()
:+
scala.collection.:+です。Seqをinitとlastに分解します。
こちらも、Vectorで。
val v = Vector(1, 2, 3)
パターンマッチ。
// initとlast v match { case init :+ 2 :+ 3 => println(s"matched!! $init") case _ => // ここには来ない } v match { case init :+ n => println(s"matched!! $init :+ $n") case _ => // ここには来ない }
結果。
matched!! Vector(1) matched!! Vector(1, 2) :+ 3
こちらも、先頭の要素を空でマッチさせることが可能みたいです。
v match { case init :+ 1 :+ 2 :+ 3 => println(s"matched!! $init") case _ => // ここには来ない }
結果。
matched!! Vector()
なるほど、こんなのがあったとは。勉強になりました〜。
追記)
このブログを公開した後で、Twitterでこのエントリに対してツッコミをもらったのですが、そういえばSeq自体でパターンマッチが可能でした。
v match { case Vector(1, rest @ _*) => println(s"matched!! $rest") case _ => // ここには来ない } v match { case Seq(1, 2, rest @ _*) => println(s"matched!! $rest") case _ => // ここには来ない }
結果。
matched!! Vector(2, 3) matched!! Vector(3)
どこかで見た記憶はありましたが、完全に忘れてましたね…。