scalaのパターンマッチについて
今回はscalaのパターンマッチについてメモ
ケースクラスとパターンマッチの組み合わせはだいぶ強力なことができるということで、ちゃんと覚えておくためのブログに残しておきます。
パターンマッチで使うmatch式はこんな感じになります。
<セレクター式> match { <選択肢> }
・match式のマッチング方法
match式では上から順番にマッチするかどうかがチェックされ、どれか1つの条件にマッチした場合、それ以降の条件に対するマッチングは行われません。
パターンマッチのパターンはいくつかありますが、その中からいくつかをまとめてみました。
1,定数パターン
2,変数パターン
3,ワイルドカードパターン
4,コンストラクタパターン
5,型付きパターン
・定数パターン
定数パターンは自分自身としかマッチしません。
ようは決め打ちの値。定数としては任意のリテラルを使えます。(string,boolean,intなど)
scala> def const(x: Any) = x match { | case 1 => "number" | case true => "true" | case "constant" => "String" | case Nil => "empty" | } const: (x: Any)String scala> const(1) res0: String = number scala> const("constant") res1: String = String scala> const(100) res2: String = something
・変数パターン
scala> def expr(x: Any) = x match { | case 0 => "ZERO" | case something => "not ZERO:" + something | } expr: (x: Any)String //マッチした変数を参照することも可能 scala> expr("hello") res1: String = not ZERO:hello
・コンストラクタパターン
前回のケースクラスについての記事で、ケースクラスに対してもパターンマッチができると書きました。下がその例です。
scala> case class Iphone(color:String, price:Int) defined class Iphone scala> def caseClassMatch(p: Iphone) = p match { | case Iphone( _, 900)=>{ | println("price is $900") | } | case Iphone( "green", _)=>{ | println("Color is green") | } | } caseClassMatch: (p: Iphone)Unit scala> val myIphone = Iphone("red", 900) myIphone: Iphone = Iphone(red,900) scala> caseClassMatch(myIphone) price is $900
ケースクラスのコンストラクタに対してパターンマッチングされていることが確認できると思います。
*ケースクラスのコンストラクタの引数にさらにケースクラスがある場合も、match式でネストされたケースクラスにもパターンマッチが可能ということ。
型でマッチさせることも可能です。
5,型付きパターン
scala> def patternMatch(n:Any) = n match { | case n:Int => println("int") | case n:String => println("string") | case n:Boolean => println("boolean") | } patternMatch: (n: Any)Unit scala> patternMatch(1) int scala> patternMatch("Good") string
以上、他の言語よりも柔軟な使い方ができるscalaのパターンマッチでした。
追記
変数を束縛(bind)する方法
scala> case class Iphone(color: String, price: Int) defined class Iphone scala> def caseClassMatch(p: Iphone) = p match { | case Iphone(_, 900) => println("900 yen") | case Iphone("green", _) => println("green!") | case Iphone(color, _) => println("color is " + color) | } caseClassMatch: (p: Iphone)Unit scala> caseClassMatch(Iphone("red", 300)) color is red
変数を束縛するという表現がピンとこなかったけど、
ワイルドカードパターンと比べてみたら理解できたので書いてみる。
・ワイルドカードのパターン
任意の条件にマッチした場合、予め決めていた処理を行う。
・変数を束縛する変数パターン
ワイルドカードと同じように任意の条件にマッチする。ここまで一緒。
違うのはこれからで、パターン変数xに値が束縛されて参照が可能になります。
上の式だとcolorに値が束縛され、参照できるようになっています。
パターンがマッチしなかった場合どうなるか?
上の例でどのパターンにもマッチしなかった場合どうなるか?という指摘があったため追記です。
結論から言うとerrorになります。下記参照
scala> case class Iphone(color:String, price:Int) defined class Iphone scala> def caseClassMatch(p: Iphone) = p match { | case Iphone( _, 900)=>{ | println("price is $900") | } | case Iphone( "green", _)=>{ | println("Color is green") | } | } caseClassMatch: (p: Iphone)Unit scala> val myPhone = Iphone("red", 100) myPhone: Iphone = Iphone(red,100) scala> caseClassMatch(myPhone) scala.MatchError: Iphone(red,100) (of class Iphone) at .caseClassMatch(<console>:9) ... 32 elided