scala學習筆記1-泛型、界定、形變、this.type、複合類型、抽象類型 原

一、Scala中的泛型
class Triple[F: ClassTag, S : ClassTag, T : ClassTag](val f : F, val s : S, val t :T)  <span style="font-family: Arial, Helvetica, sans-serif;">//其中,ClassTag在scala.reflect.ClassTag中,並且ClassTag是隱式的,可省略;</span>
val t1 = new Triple("hadoop", "spark", "bigdata");
val t2 = new Triple[String, Int, Double]("bigdata", 1, 1.0);


二、Scala中Bounds(界定)

    一般的Bounds

    <: 使得T必須是Comparable[T]的子類,這T類型的a,b纔有compareTo方法。

class Pair[T <: Comparable[T]](val a : T, val b : T)
if(a.compareTo(b)> 0) a else b
    View Bounds(視圖界定)

class Pair2 [T <% Comparable[T]](val a : T, val b :T)
<% 使得T不是Comparable[T]的子類型,隱式轉爲它的子類。比如傳入的是Int類型,Int類型沒有實現Comparable[T]。故先要將Int隱式轉爲RichInt,此時RichInt是Comparable[T]的子類
class Pair3 [T <% Ordered[T]](val a : T, val b : T)
轉爲Ordered[T],可以將對象以a > b 的形式進行比較。If(a>b) a else b,其實>是a的方法
    Context Bounds

class Pair_Ordering [T : Ordering : ClassTag](val a : T, val b : T) {
     def bigger(implicit ordered : Ordering[T]) ={
         if(ordered.compare(a, b) > 0) a else b
      }
}
T :Ordering表示存在一個隱式值爲Ordering[T]
     Manifest、classManifest、ClassTag、TypeTag

      利用Manifest可以創建泛型數組。Manifest中存儲了T的實際類型的信息,在實際運行中作爲參數運行在上下文環境中。其中T:Manifest和上文的T:Ordering都屬於Context Bounds的用法

def arrayMake[T : Manifest](a : T, b : T) = {
    val array = new Array[T](2);
    array(0) = a;
    array(1) = b;
    array;
}
         後來,Manifest和classManifest分別被TypeTag和ClassTag所取代。ClassType的限定要弱於TypeTag。ClassType提供了運行時的類型信息,而TypeTag提供了所有的靜態類型信息。而實際中,ClassType提供的運行時類型信息已經足夠使用,因此在spark等中使用廣泛。

           def arrayMake2[T : ClassTag](elems : T*) = Array[T](elems : _*)

            ,這裏可以看到T:ClassTag,自動隱式轉爲ClassTag[T]

            arrayMake2(1,2).foreach(println)

           主要是在運行時指定在編譯時無法確定的比較高級別的類別的信息,不包括static級別的type信息。

    多重界定

          T <:A with B 表示T是A或B的子類。

          T : A: B 是上下文界定。表示必須同時存在A[T]和B[T]的隱式值。

          T <% A <% B 是視圖界定,表示T可以隱式轉爲A且B。

          T>: A <: B 表示A是T的下界,B是T的上界。並且,下界A必須寫在上界B的前面,同時A一定是B的子類。

三、 Scala的類型約束

     A =:=B 表示A類型等同B類型

     A<:< B 表示A類型是B類的子類型

四、 Scala中的Variance

    Variance稱爲形變 T

       協變 +T

       逆變 –T

       class  Person[+T](first : T, second : T) 則後面的first和second的類型必須是T的父類。-T的話,表示first和second的類型必須是T的子類。

五、 Scala中的鏈式調用

     任何的類對象都有type屬性:this.type

class Animal {
  def breathe() : this.type = {
      //TODO
      this
  }
}
    
class Dog extends Animal {
 def eat() : this.type = {
    //TODO
    this
  }
}
Val dog = new Dog; dog.breathe().eat();
六、 Scala中的路徑依賴

    內部類享有外部類的實例,可以訪問外面類中的私有成員;而外部類不可以訪問內部類中的私有成員。

    Scala中內部類必須依賴於外部類的實例。外部類實例不同,則內部類也不同,依賴於外部類,稱爲路徑依賴,不同路徑下的內部類,類型不同。

class Outter {
   private[this] val x = 1
     
   class Inner {
      private[this] val y = x + 1
    }
}
 
object PathDependencies extends App {
  val out1 = new Outter
  val out2 = new Outter
 
  //out1.Inner和out2.Inner在不同路徑下,類型不同
  val inner1 : out1.Inner = new out1.Inner
  val inner2 : out2.Inner = new out2.Inner
 
  //類型投影,out1.Inner,out2.Inner是Outter#Inner的子類
  val inner3 : Outter#Inner = new out1.Inner
  val inner4 : Outter#Inner = new out2.Inner
}
七、 Scala中的結構體類型

//傳入實現get方法的匿名類實例
init(new {def get() = println("geted")})
       
//申明一個含有get方法的類型,類型於c語言中的結構體類型
type X = {//不需要像java那樣,通過接口和實現接口來限制
   def get() : Unit
}
def init1(res : X) = {
   res.get
}
init1(new {def get() = println("geted again")})
object A {def get() = println("geted In A")}
init1(A)
八、 Scala中的複合類型

trait A //接口A
trait B //接口B
class C extends A with B {//繼承A,B,實現get的C
   def get() = println("hello compoundtype!")
}
   
object CompoundType {
    //複合類型,該類型表示既是A又是B,同時還要實現get方法
    type CompoundType = A with B {def get():Unit}
 
    def init(x : CompoundType)  = {
       x.get()
    }
 
    def main(args: Array[String]): Unit = {
      init(new C)
    }
}

九、 Scala中的InfixType

object InfixType {
   def main(args: Array[String]): Unit = {
       //右結合的表達式
      "Spark" >>: "Hadoop">>: Log
       
       val list = List()
       val newList = 1 :: 2 :: list
       println(newList)
       
       class Infix_Type[A, B]
       val it : Infix_Type[Int, String] =null
       val it1 : Int Infix_Type String =null
   
       val cons =Constant("1", "2")
       cons match {
         case "1" Constant "2"=> {
          println("spark!")
         } 
       }
   }
}
case class Constant(first : String, second : String)
 object Log {
   def >>: (data : String) : Log.type = { // >>: 這是方法名
     println(data);
     Log
  }
}

十、Self Types

      自類型, 相當於對當前實例關鍵this起一個別名。用法如下://有點類似於javascript中的var self = this; 的用法

Class Outter {
   self =>
   val i
   Class Inner {
      def foo(){ println(self.i) }
   }
}
      主要用途在對this的一種限定,必須要混入另一個類型。用法如下:

trait S1
class S2 {
     this:S1=>
}
val s = new S2 with S1  //實例化S2的時候需要with S1
class S3 extends S2 with S1  //extends S2的時候需要 with S1
十一、 Scala中的依賴注入

      通過self type的用法,實現依賴組件的注入

object DependenceInjection extends App {
   T.authorize()
}
trait Logger{
   def log(msg:String)
}
class Auth{
   auth : Logger => //關鍵點
   val key = "hello di"
   def authorize() = {
     log(key)
      //TODO
   }
}
 
//T對象繼承Auth則必須with Logger實現log方法
object T extends Auth with Logger {
   override def log(msg:String) = {
     println(msg)
   }
}
十二、 Scala中的抽象類型AbstractType

     抽象類通過type聲明類型,但不指定具體的類型

     在子類中指定相關類型,和實現抽象類中的方法

trait Reader {
     type input <: java.io.Serializable //input 必須是Serializable的子類
     type results
     def read(str : input) : results
}              
class FileReader extends Reader {
    type input = String
    type results = BufferedSource
    override def read(str : input):results = {
        Source.fromFile(str)
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章