Scala模式匹配
来源:互联网 发布:apache与nginx的进程 编辑:程序博客网 时间:2024/06/14 13:13
Scala模式匹配
1 前言
Scala中的模式匹配可以看成是更好的java switch语句。比如如下java代码:
public void testSwitch(){ for(int i = 0; i < 100; i++){ switch(i){ case 10 : System.out.println("10"); break; case 50 : System.out.println("50"); //由于没有break所以会调入下一个分支 case 80 : System.out.println("80"); default : break; } }}
scala通过模式匹配解决了java switch中存在的这个问题,并且scala的模式匹配功能更加强大,请看如下代码:
def testMatch { for(i <- 1 to 100){ i match{ case 10 => println(10) case 50 => println(50) case 80 => println(80) case _ => } }}
上述scala代码展示了简单的模式匹配,它的实现方式是通过match关键字与case x=>的方式实现的,其中case _表示出了上述条件的其余匹配,类似于java中的default。
2 守卫条件
scala语言提供了更加灵活的模式匹配,你可以添加守卫条件,守卫可以是任何boolean的条件。
def testMatch { for(i <- 1 to 100){ i match{ case 0 => println(0) // 守卫条件 case _ if(i % 2 == 0) => println("i是偶数") case _ if(i % 2 != 0) => println("i是奇数") case _ => } }}
3 模式的类型
3.1 常量模式
object ConstantPattern{ def main(args: Array[String]): Unit = { //注意,下面定义的是一个函数 //函数的返回值利用的是模式匹配后的结果作为其返回值 //还需要注意的是函数定义在main方法中 //也即scala语言可以在一个函数中定义另外一个函数 def patternShow(x:Any)=x match { case 5 => "five" case true=>"true" case "test"=>"String" case null=>"null" case Nil=>"empty list" case _ =>"Other constant" } println(patternShow(5)) }}
3.2 变量模式
object VariablePattern{ def main(args: Array[String]): Unit = { def patternShow(x:Any)=x match { case 5 => "five" //所有不是值为5的都会匹配变量y //例如"xxx",则函数的返回结果就是"xxx" case y => y } println(patternShow("xxx")) }}
3.3 构造器模式
//构造器模式必须将类定义为case classcase class Person(name:String,age:Int)object ConstructorPattern { def main(args: Array[String]): Unit = { val p=new Person("摇摆少年梦",27) def constructorPattern(p:Person)=p match { case Person(name,age) => "Person" case _ => "Other" } }}
3.4 序列(Sequence)模式
序列模式指的是像Array、List这样的序列集合进行模式匹配
object SequencePattern { def main(args: Array[String]): Unit = { val p=List("spark","hive","SparkSQL") def sequencePattern(p:List[String])=p match { //只需要匹配第二个元素 case List(_,second,_*) => second case _ => "Other" } println(sequencePattern(p)) }}
3.5 元组模式
//匹配某个元组内容object TuplePattern { def main(args: Array[String]): Unit = { val t=("spark","hive","SparkSQL") def tuplePattern(t:Any)=t match { case (one,_,_) => one case _ => "Other" } println(tuplePattern(t)) }}
3.6 类型模式
//匹配传入参数的类型object TypePattern { def main(args: Array[String]): Unit = { def tuplePattern(t:Any)=t match { case t:String=> "String" case t:Int => "Integer" case t:Double=>"Double" } println(tuplePattern(5.0)) }}
上述代码如果不用模式匹配的话,要实现相同的功能,可以通过下列代码实现:
def tuplePattern2(t:Any)={ if(t.isInstanceOf[String]) "String" else if(t.isInstanceOf[Int]) "Int" else if(t.isInstanceOf[Double]) "Double" else if(t.isInstanceOf[Map[_,_]]) "MAP" }
3.7 变量绑定模式
object VariableBindingPattern{ def main(args:Array[String]):Unit = { var t = List(List(1,2,3),List(2,3,4)) def variableBindingPattern(t:Any) = t match{ //变量绑定,采用变量名(这里是e) //与@符号,如果后面的模式匹配成功,则将 //整体匹配结果作为返回 case List(_,e@List(_,_,_)) => e case _ => Nil } println(variableBindingPattern(t)) } }}//编译执行后的输出结果为 List(2, 3, 4)
4 for控制结构中的模式匹配
object PatternInForLoop { def main(args: Array[String]): Unit = { val m=Map("china"->"beijing","dwarf japan"->"tokyo","Aerican"->"DC Washington") //利用for循环对Map进行模式匹配输出, for((nation,capital)<-m) println(nation+": " +capital) }}
正则表达式中的模式匹配
object RegexMatch { def main(args: Array[String]): Unit = { val ipRegex="(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)".r for(ipRegex(one,two,three,four) <- ipRegex.findAllIn("192.168.1.1")) { println("IP子段1:"+one) println("IP子段2:"+two) println("IP子段3:"+three) println("IP子段4:"+four) } }}
5 Option类型模式匹配
Option类型有两个子类型,分别是Some和None(单例对象),下面给出的是Option类型在Scala语言中的类层次结构:
Option类其实是一个sealed class
//Option类的部分源码sealed abstract class Option[+A] extends Product with Serializable { self => /** Returns true if the option is $none, false otherwise. */ def isEmpty: Boolean /** Returns true if the option is an instance of $some, false otherwise. */ def isDefined: Boolean = !isEmpty
下面给出的分别是Some和None的源码:
/** Class `Some[A]` represents existing values of type * `A`. * * @author Martin Odersky * @version 1.0, 16/07/2003 */final case class Some[+A](x: A) extends Option[A] { def isEmpty = false def get = x}/** This case object represents non-existent values. * * @author Martin Odersky * @version 1.0, 16/07/2003 */case object None extends Option[Nothing] { def isEmpty = true def get = throw new NoSuchElementException("None.get")}
下面的代码演示了其如何应用到模式匹配中:
object OptionDemo extends App{ val m = Map("hive"->2,"spark"->3,"scala"->1) def mapPattern(t:String) = m.get(t) match{ case Some(x) =>println(x) ; x case None => println("None") ; -1 } println(mapPattern("hve"))}//输出结果为://None//-1
前面我们看到:None是一个case object,它同Some一样都extends Option类,只不过Some是case class。那么case object是什么呢?
//下面的类主要用于模拟Option,Some,None三个类或对象之间的关系sealed abstract class Acase class B(name:String,age:Int) extends Acase object CaseObject extends A{}
上述代码编译后,生成的字节码文件如下:
D:\ScalaWorkspace\ScalaChapter15\bin\cn\scala\xtwy 的目录2015/08/01 21:26 <DIR> .2015/08/01 21:26 <DIR> ..2015/08/01 21:26 515 A.class2015/08/01 21:26 1,809 B$.class2015/08/01 21:26 4,320 B.class2015/08/01 21:26 1,722 CaseObject$.class2015/08/01 21:26 1,490 CaseObject.class
单从编译后生成的类来看,它们之间似乎实现方式都一样,那到底是什么样的呢?
class A的反编译后的代码如下:
D:\ScalaWorkspace\ScalaChapter15\bin\cn\scala\xtwy>javap -private A.classCompiled from "CaseObject.scala"public abstract class cn.scala.xtwy.A { public cn.scala.xtwy.A();}
case class B对应的字节码文件反编译后如下:
D:\ScalaWorkspace\ScalaChapter15\bin\cn\scala\xtwy>javap -private B.classCompiled from "CaseObject.scala"public class cn.scala.xtwy.B extends cn.scala.xtwy.A implements scala.Product,scala.Serializable { private final java.lang.String name; private final int age; public static scala.Function1<scala.Tuple2<java.lang.String, java.lang.Object>, cn.scala.xtwy.B> tupled(); public static scala.Function1<java.lang.String, scala.Function1<java.lang.Object, cn.scala.xtwy.B>> curried(); public java.lang.String name(); public int age(); public cn.scala.xtwy.B copy(java.lang.String, int); public java.lang.String copy$default$1(); public int copy$default$2(); public java.lang.String productPrefix(); public int productArity(); public java.lang.Object productElement(int); public scala.collection.Iterator<java.lang.Object> productIterator(); public boolean canEqual(java.lang.Object); public int hashCode(); public java.lang.String toString(); public boolean equals(java.lang.Object); public cn.scala.xtwy.B(java.lang.String, int);}//自动生成的伴生对像类public final class cn.scala.xtwy.B$ extends scala.runtime.AbstractFunction2<java.lang.String, java.lang.Object, cn.scala.xtwy.B> implements scala.Serializable { public static final cn.scala.xtwy.B$ MODULE$; public static {}; public final java.lang.String toString(); public cn.scala.xtwy.B apply(java.lang.String, int); public scala.Option<scala.Tuple2<java.lang.String, java.lang.Object>> unapply(cn.scala.xtwy.B); private java.lang.Object readResolve(); public java.lang.Object apply(java.lang.Object, java.lang.Object); private cn.scala.xtwy.B$();}
case object CaseObject对应的反编译后的内容:
D:\ScalaWorkspace\ScalaChapter15\bin\cn\scala\xtwy>javap -private CaseObject.classCompiled from "CaseObject.scala"public final class cn.scala.xtwy.CaseObject { public static java.lang.String toString(); public static int hashCode(); public static boolean canEqual(java.lang.Object); public static scala.collection.Iterator<java.lang.Object> productIterator(); public static java.lang.Object productElement(int); public static int productArity(); public static java.lang.String productPrefix();}D:\ScalaWorkspace\ScalaChapter15\bin\cn\scala\xtwy>javap -private CaseObject$.classCompiled from "CaseObject.scala"public final class cn.scala.xtwy.CaseObject$ extends cn.scala.xtwy.A implementsscala.Product,scala.Serializable { public static final cn.scala.xtwy.CaseObject$ MODULE$; public static {}; public java.lang.String productPrefix(); public int productArity(); public java.lang.Object productElement(int); public scala.collection.Iterator<java.lang.Object> productIterator(); public boolean canEqual(java.lang.Object); public int hashCode(); public java.lang.String toString(); private java.lang.Object readResolve(); private cn.scala.xtwy.CaseObject$();}
对比上述代码不难看出,case object与case class所不同的是,case object对应反编译后的CaseObject$.cl
ass中不存在apply、unapply方法,这是因为None不需要创建对象及进行内容提取,从这个角度讲,它被定义为case object是十分合理的。
6 样例类(Case Class)
Case Class是一种特殊的类,能够被优化以用于模式匹配,下面代码定义了一个样例类:
abstract class Person// case class Studentcase class Student(name:String,age:Int,studentNo:Int) extends Person// case class Teachercase class Teacher(name:String,age:Int,teacherNo:Int) extends Person// case class Nobodycase class Nobody(name:String) extends Personobject CaseClassDemo{ def main(args:Array[String]):Unit = { // case class会自动生成apply方法,从而省去new操作 val p : Student = Student("tom",18,2015) // match case p match{ case Student(name,age,studentNo) => printf("%s:%d:%d\r\n",name,age,studentNo); case Teacher(name,age,teacherNo) => printf("%s:%d:%d\r\n",name,age,studentNo); case Nobody(name) => printf("%s\r\n",name); } }}
当一个类被声明为case class的时候,scala会帮助我们做下面几件事情:
1. 构造器中的参数如果不被声明为var的话,它默认就是val类型的,但是一般不推荐将构造器中的参数声明为var
2. 自动创建伴生对象,同时在里面给我们实现apply方法,使得我们在使用的时候可以不直接显示的new对象
3. 伴生对象中同样会帮我们实现unapply方法,从而可以将case class应用于模式匹配。
4. 实现 自己的toString,hashCode,copy,equals方法
除此之外,case cass与其它普通的scala泪没有区别
下面给出case class Student字节码文件内容,以验证我们上述所讲的内容
//下面的代码是自动生成的伴生对象中的字节码内容D:\ScalaWorkspace\ScalaChapter13\bin\cn\scala\xtwy>javap -private Student$.classCompiled from "CaseClass.scala"public final class cn.scala.xtwy.Student$ extends scala.runtime.AbstractFunction3<java.lang.String, java.lang.Object, java.lang.Object, cn.scala.xtwy.Student> implements scala.Serializable { public static final cn.scala.xtwy.Student$ MODULE$; public static {}; public final java.lang.String toString(); public cn.scala.xtwy.Student apply(java.lang.String, int, int); public scala.Option<scala.Tuple3<java.lang.String, java.lang.Object, java.lang.Object>> unapply(cn.scala.xtwy.Student); private java.lang.Object readResolve(); public java.lang.Object apply(java.lang.Object, java.lang.Object, java.lang.Object); private cn.scala.xtwy.Student$();}//下面的代码是Student类自身的字节码内容D:\ScalaWorkspace\ScalaChapter13\bin\cn\scala\xtwy>javap -private Student.classCompiled from "CaseClass.scala"public class cn.scala.xtwy.Student extends cn.scala.xtwy.Person implements scala.Product,scala.Serializable { private final java.lang.String name; private final int age; private final int studentNo; public static scala.Function1<scala.Tuple3<java.lang.String, java.lang.Object, java.lang.Object>, cn.scala.xtwy.Student> tupled(); public static scala.Function1<java.lang.String, scala.Function1<java.lang.Object, scala.Function1<java.lang.Object, cn.scala.xtwy.Student>>> curried(); public java.lang.String name(); public int age(); public int studentNo(); public cn.scala.xtwy.Student copy(java.lang.String, int, int); public java.lang.String copy$default$1(); public int copy$default$2(); public int copy$default$3(); public java.lang.String productPrefix(); public int productArity(); public java.lang.Object productElement(int); public scala.collection.Iterator<java.lang.Object> productIterator(); public boolean canEqual(java.lang.Object); public int hashCode(); public java.lang.String toString(); public boolean equals(java.lang.Object); public cn.scala.xtwy.Student(java.lang.String, int, int);}
7 Case Class应用
7.1 Case Class常用方法
//toString方法演示scala> val s=Teacher("john",38,1024)s: Teacher = Teacher(john,38,1024)//无参copy方法演示scala> val s1=s.copy()s1: Teacher = Teacher(john,38,1024)//copy方法是深度拷贝scala> println(s eq s1)false//equal方法根据对象内容进行比较scala> println(s equals s1)truescala> println(s == s1)true//hashcode方法scala> s1.hashCoderes45: Int = 567742485//toString方法scala> s1.toStringres46: String = Teacher(john,38,1024)//带一个参数的copy方法scala> s1.copy(name="stephen")res47: Teacher = Teacher(stephen,38,1024)//带二个参数的copy方法scala> s1.copy(name="stephen",age=58)res49: Teacher = Teacher(stephen,58,1024)//带三个参数的copy方法scala> s1.copy(name="stephen",age=58,teacherNo=2015)res50: Teacher = Teacher(stephen,58,2015)
7.2 多个参数的Case Class
abstract class Person// case class Studentcase class Student(name:String,age:Int,studentNo:Int) extends Person// case class Teachercase class Teacher(name:String,age:Int,teacherNo:Int) extends Person// case class Nobodycase class Nobody(name:String) extends Person// SchoolClass为接受多个Person类型的参数的类case class SchoolClass(classDescription:String, persons : Person*)// 下列代码给出的是其模式匹配应用示例object CaseClassDemo{ def main(args:Array[String]):Unit { val sc = SchoolClass("scala培训班",Teacher("tom",24,324),Student("zhangsan",12,2118)) sc match{ case SchoolClass(_,_,Student(name,age,studentNo)) => println(name) case _ => println("Nobody") } }}
7.3 sealed case class
在进行模式匹配的时候,有些时候需要确保所有的可能情况都被列出,此时常常会将case class的超类定义成sealed(密封类)
// Person最前面加上sealedsealed abstract class Person// case class Studentcase class Student(name:String,age:Int,studentNo:Int) extends Person// case class Teachercase class Teacher(name:String,age:Int,teacherNo:Int) extends Person// case class Nobodycase class Nobody(name:String) extends Personobject CaseClassDemo{ def main(args:Array[String]):Unit = { // case class会自动生成apply方法,从而省去new操作 val p : Student = Student("tom",18,2015) // 这边仅仅给出了Student的情况,在编译时 // 编译器会提示 // match may not be exhaustive.It would fail on the following inputs:Nobody(_),Teacher(_,_,_) p match{ case Student(name,age,studentNo) => printf("%s:%d:%d\r\n",name,age,studentNo); } }}
7.4 Case Class在
参考博文
https://yq.aliyun.com/articles/60380?spm=5176.8251999.569296.14.2c75dfe7HfF6nm
https://yq.aliyun.com/articles/60379?spm=5176.8251999.569296.15.2c75dfe7HfF6nm
- scala 正则匹配(模式匹配)
- scala简要:模式匹配
- Scala模式匹配
- Scala 模式匹配
- Scala中的模式匹配
- scala 模式匹配
- Scala之模式匹配
- Scala的模式匹配
- Scala模式匹配
- scala的模式匹配
- Scala 之 模式匹配
- Scala之模式匹配
- scala模式匹配·
- Scala模式匹配
- Scala模式匹配
- scala模式匹配
- scala基础-模式匹配
- Scala模式匹配
- 利用Python做数据分析——numpy基础
- Linux环境下安装yafu
- Tomcat access log配置
- 用户权限控制 ----- Auth认证(lumen篇)
- python多线程编程
- Scala模式匹配
- PHPSTORM配置 PHP 单元测试
- hdu4112-规律&二进制- Break the Chocolate
- C
- Pan Download(百度网盘高速下载器)单文件版V1.4.3下载 | pandownload1.4.3
- 打劫房屋-LintCode
- < 笔记 > Python
- 关于vue-cli项目npm run build后,index.html无法在浏览器打开
- 数据结构-数组排序-二路归并-循环实现-C语言