Scala入門到精通——第十五節 Case Class與模式匹配(二)
本節主要內容
- 模式匹配的型別
- for控制結構中的模式匹配
- option型別模式匹配
1. 模式的型別
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))
}
}
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 構造器模式
//構造器模式必須將類定義為case class
case 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"
}
}
}
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))
}
}
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))
}
}
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"
}
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(_,[email protected]List(_,_,_)) => e
case _ => Nil
}
println(variableBindingPattern(t))
}
}
//編譯執行後的輸出結果為 List(2, 3, 4)
2. 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)
}
}
}
3. Option型別模式匹配
在前面的課程內容中,我們曾經提到過Option型別,Option型別有兩個子類,分別是Some和None(單例物件),本小節將從模式匹配的角度對Option類進行重新思考。
下面給出的是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,"Spark MLlib"->4)
def mapPattern(t:String)=m.get(t) match {
case Some(x) => println(x);x
case None => println("None");-1
}
println(mapPattern("Hive"))
}
//輸出結果為:
//None
//-1
前面我們看到:None是一個case object,它同Some一樣都extends Option類,只不過Some是case class,對於case class我們已經很熟悉了,那case object它又是怎麼樣的呢?假設我們定義了以下類:
//下面的類主要用於模擬Option,Some,None三個類或物件之間的關係
sealed abstract class A
case class B(name:String,age:Int) extends A
case 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.class
2015/08/01 21:26 1,809 B$.class
2015/08/01 21:26 4,320 B.class
2015/08/01 21:26 1,722 CaseObject$.class
2015/08/01 21:26 1,490 CaseObject.class
單從編譯後生成的類來看,它們之間似乎實現方式都一樣,那到底是什麼樣的呢?
class A的反編譯後的程式碼如下:
D:\ScalaWorkspace\ScalaChapter15\bin\cn\scala\xtwy>javap -private A.class
Compiled 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.class
Compiled from "CaseObject.scala"
public class cn.scala.xtwy.B extends cn.scala.xtwy.A implements scala.Product,sc
ala.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.Obje
ct, 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.cla
ss
Compiled 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$.cl
ass
Compiled from "CaseObject.scala"
public final class cn.scala.xtwy.CaseObject$ extends cn.scala.xtwy.A implements
scala.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是十分合理的。
新增公眾微訊號,可以瞭解更多最新Spark、Scala相關技術資訊