1. 程式人生 > >大資料之scala(四) --- 模式匹配,變數宣告模式,樣例類,偏函式,泛型,型變,逆變,隱式轉換,隱式引數

大資料之scala(四) --- 模式匹配,變數宣告模式,樣例類,偏函式,泛型,型變,逆變,隱式轉換,隱式引數

一、模式匹配:當滿足case條件,就終止
----------------------------------------------------------
    1.更好的switch
        var x = '9';
        x match{
            case '+' => println(" +++ ")
            case '-' => println(" --- ")
            case _ if Character.isDigit(x) => print("is number!");  //帶守護條件
            case _   => println(" *** ")                            //相當於 case 中的default
        }

    2.匹配型別
        val x:Any = '1';            //Any所有型別的超類
        x match{
            case a:String => println("is String")
            case b:Int => println("is Int")
            case _ => println("****")
        }

    3.匹配陣列
        val arr = Array(0,2)
        arr match {
            case Array(0,1) => println("是陣列0,1")            //匹配陣列是否是Array(0,1)
            case Array(x,y) => println("是兩個元素的陣列")      //匹配陣列是否只有2個元素
            case Array(0,_*) => println("是以0開始的陣列")      //匹配陣列是否以0為第一個元素
            case _ => println("***")                           //default
        }


二、變數宣告模式
--------------------------------------------
    val x = 100 ;        //
    val t = (1,2,3,4) ;       //元組
    t _1                    //訪問元組的第1個元素
    t._1                    //訪問元組的第1個元素
    val (a,b,c, d) = t       //解析元組中組員.將元組中的前三個元素賦值給 a,b,c,d


三、樣例類 :主要用於模式匹配
-----------------------------------------------
    1.主要用於模式匹配.內建了apply和unapply方法,實現了序列化等介面。建立物件時不需要使用new.
        abstract class Dog{}
        case class Jing8(name:String) extends Dog{}
        case class Shapi(age:Int) extends Dog{}

        //新建物件不需要new,直接應用apply方法
        scala> val d = Jing8("tom")
        d: Jing8 = Jing8(tom)

        //模式匹配
        val d:Dog = new Jing8("tom");
        d match{
            case Jing8(name) => print("是Jing8 : " + name);
            case Shapi(age) => print("是Shapi : " + age);
            case _ => print("aishiuihsui");
        }

    2.密封樣例類
        子類和父類必須定義在同一檔案中。父類用sealed宣告
        sealed abstract class Dog{}
        case class Jing8(name:String) extends Dog{}
        case class Shapi(age:Int) extends Dog{}

四、偏函式
------------------------------------------------
    val f:PartialFunction[Char,Int] = {
        case '+' => 1 ;
        case '-' => -1
        case _ => 0
    }

    scala> f('+')
    res214: Int = 1

    scala> f('-')
    res215: Int = -1

    scala> f('*')
    res216: Int = 0


五、泛型
----------------------------------------------------
    1.泛型類
        //定義一個帶有兩個型別引數T和S的類。
        class Pair[T,S] (val first:T , val second :S ){    ...    }
        val p = new Pair(42,"String");              // T :Int S :String
        val p = new Pair[Any,Any](42,"String");      // T :Int S :String

    2.泛型函式
        def getMiddle[T] (a:Array[T]) = {
            a(a.length / 2);
        }

        scala> getMiddle(Array(1,2,3,4))
        res218: Int = 3

    3.泛型的界
        a.變數型別的限定
            //要求2個引數的型別相同
            class Pair[T](val first:T , val second :T )

        b. <: 上界:要求泛型T必須是指定的型別的子類
            //泛型T必須是Dog的子類
            def run[T <: Dog](d:T) = println("hello")

        b. >: 下界:要求泛型T必須是指定的型別的超類
            //泛型T必須是Dog的超類
            def run[T >: Dog](d:T) = println("hello")

        c. <% : 要求泛型T必須可以隱式轉換成指定型別


六、型變/逆變
------------------------------------------------------
    1.型變[+T]
        class Pair[T] (val first : T, val second : T)
        def makeFriends(p : Pair[Person])       //函式makeFriends的引數p的型別是Pair[Person]
        已知,Student 是 Person的子類,
        但是 makeFriends(new Pair[Person]()) 可以
             makeFriends(new Pair[Student]()) 不可以
        因為雖然Student 是 Person的子類,但是Pair[Person] 和 Pair[Student]沒有關係

        如果想Pair[Person] 和 Pair[Student],也具有Student 和 Person一樣的關係,就需要宣告型變
        class Pair[+T] (val first : T, val second : T)      //+T,表示 pair與T具有相同的繼承關係

    2.逆變[-T] -- 型變的反向
        如果,class Pair[-T] (val first : T, val second : T)
        已知,Student 是 Person的子類,
        那麼, Pair[Student] 就是 Pair[Person] 的父類


七、隱式轉換
----------------------------------------------------------
    1.隱式轉換函式
        使用implicit修飾的具有一個引數的函式。把一種型別變換成另外一種型別
            //定義隱式轉換函式,當整數和Dog之間可以隱式轉換。Dog相當於整數
            //對於int2Dog,是將n:Int的值,賦值給沙皮狗的年齡
            implicit def int2Dog(n:Int) = Shapi(n)
            //run()函式可以傳遞Dog物件,也可以傳遞整數
            def run(d:Dog) = print("hello world");
            //呼叫隱式轉換函式。
            scala> run(100) ;
            hello world

    2.在單例物件中定義隱式轉換函式
        //定義單例物件
        object DogUtil{
            //定義隱式轉換函式
            implicit def str2Dog(s:String) = Jing8(s) ;
        }

        def run3(d:Dog) = println("hello world");

        scala> run3(Jing8("tom"))
        hello world

        //錯誤是因為,方法是定義在單例類中的,需要先匯入才能使用
        scala> run3("tom")
        <console>:17: error: type mismatch;
         found   : String("tom")
         required: Dog
               run3("tom")

        //匯入之後就OK了
        scala> import DogUtil._
        import DogUtil._

        scala> run3("tom")
        hello world


八、隱式引數
--------------------------------------------------------------
    1.引數預設值和帶名引數
        def decorate(prefix:String = "[[[",c:String,suffix:String="]]]") = ...
        decorate(c= "hello world")

    2.如果有50個函式,都有一個相同的引數,而且這個相同的引數具有相同的值。那麼就需要隱式引數了

        //建立隱式變數,dog ==> Jing8("tomas")
        object DogUtil2{
            implicit val dog = Jing8("tomas") ;
        }

        import DogUtil2._
        //建立帶有隱式引數的函式
        def run4(implicit dog:Jing8) = println("hello : ") ;

        run4();