1、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);javascript
2、Scala中Bounds(界定)java
通常的Bounds數組
<: 使得T必須是Comparable[T]的子類,這T類型的a,b纔有compareTo方法。ide
class Pair[T <: Comparable[T]](val a : T, val b : T)
if(a.compareTo(b)> 0) a else b
View Bounds(視圖界定)oop
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 Boundsthis
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、TypeTagspa
利用Manifest能夠建立泛型數組。Manifest中存儲了T的實際類型的信息,在實際運行中做爲參數運行在上下文環境中。其中T:Manifest和上文的T:Ordering都屬於Context Bounds的用法scala
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的子類。
3、 Scala的類型約束
A =:=B 表示A類型等同B類型
A<:< B 表示A類型是B類的子類型
4、 Scala中的Variance
Variance稱爲形變 T
協變 +T
逆變 –T
class Person[+T](first : T, second : T) 則後面的first和second的類型必須是T的父類。-T的話,表示first和second的類型必須是T的子類。
5、 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();
6、 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
}
7、 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)
8、 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)
}
}
9、 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
}
}
10、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
11、 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)
}
}
12、 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) } }