Scala中的模式匹配

匿名 (未验证) 提交于 2019-12-02 23:57:01

1.匹配基本类型

1.观察如下实例:

object Demo_037 {   def main(args: Array[String]): Unit = {     val oper = '#'     val n1 = 20     val n2 = 10     var res = 0     oper match {       case '+' => res = n1 + n2       case '-' => res = n1 - n2       case '*' => res = n1 * n2       case '/' => res = n1 / n2       case _ => println("oper error")     }     println("res=" + res)    } } 

  1. 如果所有case都不匹配,那么会执行case _ 分支,类似于Java中default语句
  2. 如果所有case都不匹配,又没有写case _ 分支,那么会抛出MatchError
  3. 每个case中,不用break语句,自动中断case
  4. 可以在match中使用其它类型,而不仅仅是字符
  5. => 等价于 java swtich 的 :
  6. => 后面的代码块到下一个 case, 是作为一个整体执行,可以使用{} 扩起来,也可以不扩。

2.如果存在多个默认匹配的情况,则只有一个会生效

object Demo_039 {   def main(args: Array[String]): Unit = {     for (ch <- "+-3!") {       var sign = 0       var digit = 0       ch match {         case '+' => sign = 1         case '-' => sign = -1         // 可以有多个默认匹配,但是后面的默认匹配没有生效,程序也没报错         case _  => digit = 3         case _  => sign = 2       }       println(ch + " " + sign + " " + digit)     }   } } 

 

3. 默认匹配放到match的首行时,只会执行默认匹配

object Demo_040 {   def main(args: Array[String]): Unit = {     for (ch <- "+-3!") {       var sign = 0       var digit = 0       ch match {           //默认匹配放到match的首行时,后面的匹配不生效         case _  => digit = 3         case '+' => sign = 1         case '-' => sign = -1       }       println(ch + " " + sign + " " + digit)     }   } } 

  输出结果

2.守卫

object Demo_038 {   def main(args: Array[String]): Unit = {     for (ch <- "+-3!") {       var sign = 0       var digit = 0       ch match {         case '+' => sign = 1         case '-' => sign = -1         //case _ 后出现守卫条件则不表示默认匹配,表示的是忽略所传入的char         case _ if ch.toString.equals("3") => digit = 3         case _ => sign = 2  //默认匹配       }       println(ch + " " + sign + " " + digit)     }   } } 

  输出结果为

3.模式中的变量

如果在case关键字后跟变量名,那么match前表达式的值会赋给那个变量

object Demo_041 {   def main(args: Array[String]): Unit = {     val ch = 'V'     ch match {       case '+' => println("other~")       case mychar => println("wise~" + mychar)       case _ => println ("say~~")     }   } } 

  输出结果

4.类型匹配

object Demo_041 {   def main(args: Array[String]): Unit = {     // 类型匹配, obj 可能有如下的类型     val a = 7     val obj = if(a == 1) 1     else if(a == 2) "2"     else if(a == 3) BigInt(3)     else if(a == 4) Map("aa" -> 1)     else if(a == 5) Map(1 -> "aa")     else if(a == 6) Array(1, 2, 3)     else if(a == 7) Array("aa", 1)     else if(a == 8) Array("aa")      val result = obj match {       case a : Int => a       case b : Map[String, Int] => "对象是一个字符串-数字的Map集合"       case c : Map[Int, String] => "对象是一个数字-字符串的Map集合"       case d : Array[String] => "对象是一个字符串数组"       case e : Array[Int] => "对象是一个数字数组"       case f : BigInt => Int.MaxValue       case _ => "啥也不是"     }     println(result)    } } 

  1. Map[String, Int] 和Map[Int, String]是两种不同的类型,其它类推。
  2. 在进行类型匹配时,编译器会预先检测是否有可能的匹配,如果没有则报错.
  3. 如果 case _ 出现在match 中间,则表示隐藏变量名,即不使用,而不是表示默认匹配。

5.匹配数组

1.Array(0) 匹配只有一个元素且为0的数组。

2.Array(x,y) 匹配数组有两个元素,并将两个元素赋值为x和y。当然可以依次类推Array(x,y,z) 匹配数组有3个元素的等等....

3.Array(0,_*) 匹配数组以0开始

实例:匹配不同元素的数组

object Demo_042 {   def main(args: Array[String]): Unit = {     for (arr <- Array(Array(0), Array(1, 0), Array(0, 1, 0),       Array(1, 1, 0), Array(1, 1, 0, 1))) {       val result = arr match {         case Array(0) => "0"         case Array(x, y) => x + "=" + y         case Array(0, _*) => "以0开头和数组"         case _ => "什么集合都不是"       }       println("result = " + result)     }   } } 

  输出结果

6.匹配列表

实例:匹配各个列表

object Demo_043 {   def main(args: Array[String]): Unit = {     for (list <- Array(List(0), List(1, 0), List(0, 0, 0), List(1, 0, 0))) {       val result = list match {         case 0 :: Nil => "0" //匹配只有一个元素,且元素为0的列表         case x :: y :: Nil => x + " " + y //匹配有两个元素的列表,列表内元素任意         case 0 :: tail => "0 ..."          case _ => "something else"       }       println(result)     }   } } 

  运行结果

7.匹配元组

object Demo_044 {   def main(args: Array[String]): Unit = {     // 元组匹配     for (pair <- Array((0, 1), (1, 0), (1, 1),(1,0,2))) {       val result = pair match { //         case (0, _) => "0 ..." //         case (y, 0) => y //         case _ => "other" //.       }       println(result)     }   } } 

  运行结果

8.对象匹配

对象匹配,什么才算是匹配呢?

规则如下:

  • case中对象的unapply方法(对象提取器)返回Some集合则为匹配成功
  • 返回none集合则为匹配失败

实例:求平方根

object Demo_045 {   def main(args: Array[String]): Unit = {     object Square {       def unapply(z: Double): Option[Double] = Some(math.sqrt(z))//如果返回的some中有值,则表示匹配成功,否则匹配失败       def apply(z: Double): Double = z * z     }     // 模式匹配使用:     val number: Double = Square(36.0)     number match {       case Square(n) => println(n)       case _ => println("nothing matched")     }   } } 

 

实例2

object Demo_046 {   def main(args: Array[String]): Unit = {     object Names {       def unapplySeq(str: String): Option[Seq[String]] = {         if (str.contains(",")) Some(str.split(","))         else None       }     }     val namesString = "Alice,Bob,Thomas"     //说明     namesString match {       case Names(first, second, third) => {         println("the string contains three people's names")         // 打印字符串         println(s"$first $second $third")       }       case _ => println("nothing matched")     }   } } 

  运行结果

当case 后面的对象提取器方法的参数为多个,则会默认调用def unapplySeq() 方法

如果unapplySeq返回是Some,获取其中的值,判断得到的sequence中的元素的个数是否是三个,如果是三个,则把三个元素分别取出,赋值给first,second和third

其它的规则不变.

9.变量声明中的模式

match中每一个case都可以单独提取出来,意思是一样的

object Demo_047 {  def main(args: Array[String]): Unit = {    val (x, y) = (1, 2)    val (q, r) = BigInt(10) /% 3  //说明  q = BigInt(10) / 3,r = BigInt(10) % 3    val arr = Array(1, 7, 2, 9)    val Array(first, second, _*) = arr // 提出arr的前两个元素    println(x,y)    println(q,r)    println(first, second)  }}

  输出结果

object Demo_048 {   def main(args: Array[String]): Unit = {     val map = Map("A"->1, "B"->0, "C"->3)     for ( (k, v) <- map ) {       print(k + " -> " + v+"\t")     }     println()     //说明只变量出value=0的(key,value),其他舍弃     for ((k, 0) <- map) {       println(k + " --> " + 0)     }     //说明,等同于上面的,只是使用了守卫     for ((k, v) <- map if v == 0) {       println(k + " ---> " + v)     }   } } 

11.样例类

当我们有一个类型为Amount的对象时,可以用模式匹配来匹配他的类型,并将属性值绑定到变量(即:把样例类对象的属性值提取到某个变量,该功能有用)

实例1

object Demo_049 {   def main(args: Array[String]): Unit = {     for (amt <- Array(Dollar(1000.0), Currency(1000.0, "RMB"), NoAmount)) {       val result = amt match {         //说明         case Dollar(v) => "$" + v         //说明         case Currency(v, u) => v + " " + u         case NoAmount => ""       }       println(amt + ": " + result)     }    } } abstract class Amount case class Dollar(value: Double) extends Amount case class Currency(value: Double, unit: String) extends Amount case object NoAmount extends Amount 

  输出结果

观察Dollar或Currency编译后的java字节码 

public class Currency extends Amount   implements Product, Serializable {   private final double value;   private final String unit;    public static Option<Tuple2<Object, String>> unapply(Currency paramCurrency)   {     return Currency..MODULE$.unapply(paramCurrency);   }    public static Currency apply(double paramDouble, String paramString)   {     return Currency..MODULE$.apply(paramDouble, paramString);   }    public static Function1<Tuple2<Object, String>, Currency> tupled()   {     return Currency..MODULE$.tupled();   }    public static Function1<Object, Function1<String, Currency>> curried()   {     return Currency..MODULE$.curried();   }    public double value()   {     return this.value; }    public String unit() { return this.unit; }    public Currency copy(double value, String unit) { return new Currency(value, unit); }    public double copy$default$1() { return value(); }    public String copy$default$2() { return unit(); }    public String productPrefix() { return "Currency"; }    public int productArity() { return 2; }    public Object productElement(int x$1) { int i = x$1; switch (i) { default:       throw new IndexOutOfBoundsException(BoxesRunTime.boxToInteger(x$1).toString());     case 1:       break;     case 0: } return BoxesRunTime.boxToDouble(value()); }    public Iterator<Object> productIterator() { return ScalaRunTime..MODULE$.typedProductIterator(this); }    public boolean canEqual(Object x$1) { return x$1 instanceof Currency; }    public int hashCode() { int i = -889275714; i = Statics.mix(i, Statics.doubleHash(value())); i = Statics.mix(i, Statics.anyHash(unit())); return Statics.finalizeHash(i, 2); }    public String toString() { return ScalaRunTime..MODULE$._toString(this); }    public boolean equals(Object x$1) { if (this != x$1) { Object localObject = x$1;       int i;       if ((localObject instanceof Currency)) i = 1; else i = 0; if (i == 0) break label97; Currency localCurrency = (Currency)x$1; if (value() == localCurrency.value()) { str = localCurrency.unit();         String tmp55_45 = unit(); if (tmp55_45 == null) { tmp55_45; if (str == null) break label76; tmpTernaryOp = tmp55_45; break label89; }  }  }  }    public Currency(double value, String unit) {     Product.class.$init$(this);   } } 

  

样例类的copy方法和带名参数 copy创建一个与现有对象值相同的新对象,并可以通过带名参数来修改某些属性。

val amt = Currency(29.95, "RMB") val amt1 = amt.copy() //创建了一个新的对象,但是属性值一样 val amt2 = amt.copy(value = 19.95) //创建了一个新对象,但是修改了货币单位 val amt3 = amt.copy(unit = "英镑")//.. println(amt) println(amt2) println(amt3) 

 输出结果

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!