最近周りでScalaが盛り上がっているのでつられて勉強中。
パターンマッチングでどのようなものが使えるのかサンプル込みでまとめられた資料が 見あたらなかったので、仕様書を見つつメモ。 (まだ理解があやふやなので内容は怪しいですが。。)
var x = 0 var _ = 0
var x: Int = 0
8.2 Type Patternsに
The bottom types scala.Nothing and scala.Null cannot be used as type patterns, because they would match nothing in any case.
とあるように、Nothing、Nullは指定できない。
scala> null match { case x: Null => 0 } <console>:6: error: this type cannot be used in a type pattern
でも、Nullは定義文としては使える。
scala> var x: Null = null x: Null = null
他にもこのパターンはいろいろな書き方があるっぽいけど、 今は手に余るのでとりあえずパス。
0 match { case 0 => 1 }
定義文とmatch式で使えるパターンはほぼ同じようなので以下のようなことも可能。
var 0 = 0
2つの引数を受け取り値が等しいかどうかを判定する関数fを考える。
def f(x: Int, y: Int): Boolean = x match { case y => true case _ => false }
上記のように書くと、「case y」のyがvariable patternと見なされるため 「case _」がerror: unreachable codeとなりコンパイルすら通らない。
これを回避するのがこのパターン。
def f(x: Int, y: Int): Boolean = x match { case `y` => true case _ => false }
def f(x: Int, Y: Int): Boolean = x match { case Y => true case _ => false }
case classによるマッチングのこと。
scala> var (a, b) = (0, 1) a: Int = 0 b: Int = 1
unapply、unapplySeqを定義したオブジェクトを利用するマッチングのこと。 文法的にはConstructor Patternsと同じで以下のような感じ。
object A { def unapply(x: Int) = Some(x) } 0 match { case A(0) => 0 case _ => 1 } // => 0 1 match { case A(0) => 0 case _ => 1 } // => 1
case classは「自動でapply、unapplyが定義されるクラス」と説明されることが多いが、 一応仕様としては別物のよう。
簡単に言えば、Constructor PatternやExtractor Patternで@(Haskellのas-patternと同じ)や_*が使えるということかと。
scala> var List(a, b@_*) = List(1,2) a: Int = 1 b: Seq[Int] = List(2)
上記の中置記法版。
scala> var a List b = List(1,2) a: Int = 1 b: Int = 2 scala> var a List (b, c) = List(1,2,3) a: Int = 1 b: Int = 2 c: Int = 3
この場合、_*は使えない。
scala> var a List (b, _*) = List(1,2,3) <console>:1: error: illegal start of simple pattern
1 match { case 1 | 2 => 3 }
ちなみに「1 | _」は出来るけど、 「1 | x」はNG。
scala> var <t>{a}</t> = <t>0</t> a: scala.xml.Node = 0
Scala 2.0以降は無くなった、とのこと。 ほかにもちょこちょこと書いてあるんだけど、具体的にどういうことなのかよく分からず。
これも、いまいちよく分からない。。