1、類型參數1es6
一、介紹數組
類型參數是什麼?類型參數其實就相似於Java中的泛型。先說說Java中的泛型是什麼,好比咱們有List a = new ArrayList(),接着a.add(1),沒問題,a.add("2"),
而後咱們a.get(1)== 2,對不對?確定不對了,a.get(1)獲取的實際上是個String一"2",String---"2"怎麼可能與一個Integer類型的2相等呢?
因此Java中提出了泛型的概念,其實也就是類型參數的概念,此時能夠用泛型建立List,List a = new ArrayList[Integer](),那麼,此時a.add(1)沒問題,
而a.add("2")呢?就不行了,由於泛型會限制,只能往集合中添加Integer類型,這樣就避免了上述的問題。
那麼Scala的類型參數是什麼?其實意思與Java的泛型是同樣的,也是定義-種類型參數,好比在集合,在類,在函數中,定義類型參數,而後就能夠保證使用到該類型
參數的地方,就確定,也只能是這種類型。從而實現程序更好的健壯性。
此外,類型參數是Spark源碼中很是常見的,所以一樣必須掌握,才能看懂spark源碼。
二、泛型類ide
// 泛型類,顧名思義,其實就是在類的聲明中,定義一些泛型類型,而後在類內部,好比field或者method,就可使用這些泛型類型。 // 使用泛型類,一般是須要對類中的某些成員,好比某些field和method中的參數或變量,進行統一的類型限制,這樣能夠保證程序更好的健壯性和穩定性。 // 若是不使用泛型進行統一的類型限制,那麼在後期程序運行過程當中,不免會出現問題,好比傳入了不但願的類型,致使程序出問題。 // 在使用類的時候,好比建立類的對象,將類型參數替換爲實際的類型,便可。 // Scala自動推斷泛型類型特性:直接給使用了泛型類型的field賦值時,Scala會自動進行類型推斷。 案例:新生報到,每一個學生來自不一樣的地方,id多是Int,多是String scala> :paste // Entering paste mode (ctrl-D to finish) class Student[T](val localld: T) { def getSchool(hukouId: T) = "S-" + hukouId + "-" + localld } // Exiting paste mode, now interpreting. defined class Student scala> val leo = new Student[Int](111) #已經定義爲Int類型 leo: Student[Int] = Student@5680a178 scala> leo.getSchool("222") #字符串不行 <console>:13: error: type mismatch; found : String("222") required: Int leo.getSchool("222") ^ scala> leo.getSchool(222) res1: String = S-222-111 scala> val jack = new Student[String]("aaa") jack: Student[String] = Student@10bdf5e5 scala> jack.getSchool(444) <console>:13: error: type mismatch; found : Int(444) required: String jack.getSchool(444) ^ scala> jack.getSchool("444") res3: String = S-444-aaa
三、泛型函數函數
// 泛型函數,與泛型類相似,能夠給某個函數在聲明時指定泛型類型,而後在函數體內,多個變量或者返回值之間,就可使用泛型類型進行聲明,從而對某個特殊的
變量,或者多個變量,進行強制性的類型限制。
// 與泛型類同樣,你能夠經過給使用了泛型類型的變量傳遞值來讓Scala自動推斷泛型的實際類型,也能夠在調用函數時,手動指定泛型類型。
案例:卡片售賣機,能夠指定卡片的內容,內容能夠是String類型或Int類型
scala> :paste
// Entering paste mode (ctrl-D to finish)
def getCard[T](content: T) = {
if (content.isInstanceOf[Int]) "int card: " + content
else if (content.isInstanceOf[String]) "string card: " + content
else "card: " + content
}
// Exiting paste mode, now interpreting.
getCard: [T](content: T)String
scala> getCard[Int](100)
res4: String = int card: 100
scala> getCard(100)
res5: String = int card: 100
scala> getCard("100")
res6: String = string card: 100
四、上邊界Boundsui
// 在指定泛型類型的時候,有時,咱們須要對泛型類型的範圍進行界定,而不是能夠是任意的類型。好比,咱們可能要求某個泛型類型,它就必須是某個類的子類, 這樣在程序中就能夠放心地調用泛型類型繼承的父類的方法,程序才能正常的使用和運行。此時就可使用上下邊界Bounds的特性。 // Scala的上下邊界特性容許泛型類型必須是某個類的子類,或者必須是某個類的父類 案例:在派對上交朋友 scala> :paste // Entering paste mode (ctrl-D to finish) class Person(val name: String) { def sayHello = println("hello I'm " + name) def makeFriends(p: Person) { sayHello p.sayHello } } class Student(name: String) extends Person(name) class Party[T <: Person](p1: T, p2: T) { def play = p1.makeFriends(p2) } // Exiting paste mode, now interpreting. defined class Person defined class Student defined class Party scala> class Worker(val name: String) defined class Worker scala> val leo = new Student("leo") leo: Student = Student@4b0b0854 scala> val tom = new Worker("tom") tom: Worker = Worker@243c4f91 scala> val party = new Party(leo, tom) #tom是Worker類型 <console>:16: error: inferred type arguments [Object] do not conform to class Party's type parameter bounds [T <: Person] val party = new Party(leo, tom) ^ <console>:16: error: type mismatch; found : Student required: T val party = new Party(leo, tom) ^ <console>:16: error: type mismatch; found : Worker required: T val party = new Party(leo, tom) ^
五、下邊界Boundsthis
// 除了指定泛型類型的上邊界,還能夠指定下邊界,即指定泛型類型必須是某個類的父類
案例:領身份證
scala> class Father(val name: String)
defined class Father
scala> class Child(name: String) extends Father(name)
defined class Child
scala> def getLostIDCard[T >: Child](p: T) {
| if (p.getClass == classOf[Child]) println("please tell us your parents' names")
| else if (p.getClass == classOf[Father]) println("please sign your name to get your child's lost id card.")
| else println("sorry, you are not allowed to get this id card.")
| }
getLostIDCard: [T >: Child](p: T)Unit
scala> class Worker(val name: String)
defined class Worker
scala> val tom = new Worker("tom")
tom: Worker = Worker@45ca843
scala> getLostIDCard(tom)
sorry, you are not allowed to get this id card.
scala> val jack = new Father("jack")
jack: Father = Father@78123e82
scala> val leo = new Child("leo")
leo: Child = Child@58d75e99
scala> getLostIDCard(jack)
please sign your name to get your child's lost id card.
scala> getLostIDCard(leo)
please tell us your parents' names
2、類型參數2es5
一、View Boundsspa
// 上下邊界Bounds,雖然可讓一種泛型類型,支持有父子關係的多種類型。可是,在某個類與上下邊界Bounds指定的父子類型範圍內的類都沒有任何關係,則默認是
確定不能接受的。
// 然而,View Bounds做爲一種上下邊界Bounds的增強版,支持能夠對類型進行隱式轉換,將指定的類型進行隱式轉換後,再判斷是否在邊界指定的類型範圍內
案例:跟小狗交朋友
class Person(val name: String) {
def sayHello = println("Hello, I'm " + name)
def makeFriends(p: Person) {
sayHello
p.sayHello
}
}
class Student(name: String) extends Person(name)
class Dog(val name: String) { def sayHello = println("Wang, Wang, I'm " + name) }
implicit def dog2person(dog: Object): Person = if(dog.isInstanceOf[Dog]) {val _dog = dog.asInstanceOf[Dog]; new Person(_dog.name) } else Nil
二、Context Boundsscala
// Context Bounds是一種特殊的Bounds,它會根據泛型類型的聲明,好比「T: 類型」要求必須存在一個類型爲「類型[T]」的隱式值。其實我的認爲,Context Bounds之因此叫Context,是由於它基於的是一種全局的上下文,須要使用到上下文中的隱式值以及注入。
案例:使用Scala內置的比較器比較大小
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Calculator[T: Ordering] (val number1: T, val number2: T) {
def max(implicit order: Ordering[T]) = if (order.compare(number1, number2) > 0)
number1 else number2
}
// Exiting paste mode, now interpreting.
defined class Calculator
scala> val cal = new Calculator(1,2)
cal: Calculator[Int] = Calculator@60c6f5b
scala> cal.max
res0: Int = 2
三、Manifest Context Boundscode
// 在Scala中,若是要實例化一個泛型數組,就必須使用Manifest Context Bounds。也就是說,若是數組元素類型爲T的話,須要爲類或者函數定義[T: Manifest]泛型類型,這樣才能實例化Array[T]這種泛型數組。 案例:打包飯菜(一種食品打成一包) scala> class Meat(val name: String) defined class Meat scala> class Vegetable(val name: String) defined class Vegetable scala> :paste // Entering paste mode (ctrl-D to finish) def packageFood[T: Manifest] (foods: T*) = { val foodPackage = new Array[T](foods.length) for (i <- 0 until foods.length) foodPackage(i) = foods(i) foodPackage } // Exiting paste mode, now interpreting. packageFood: [T](foods: T*)(implicit evidence$1: Manifest[T])Array[T] scala> val gongbaojiding = new Meat("gongbaojiding") gongbaojiding: Meat = Meat@295cf707 scala> val yuxiangrousi = new Meat("yuxiangrousi") yuxiangrousi: Meat = Meat@6b58b9e9 scala> val shousiyangpai = new Meat("shousiyangpai") shousiyangpai: Meat = Meat@125290e5 scala> val meatPackage = packageFood(gongbaojiding, yuxiangrousi, shousiyangpai) meatPackage: Array[Meat] = Array(Meat@295cf707, Meat@6b58b9e9, Meat@125290e5) scala> val qingcai = new Vegetable("qingcai") qingcai: Vegetable = Vegetable@319988b0 scala> val baicai = new Vegetable("baicai") baicai: Vegetable = Vegetable@78aea4b9 scala> val huanggua = new Vegetable("huanggua") huanggua: Vegetable = Vegetable@47428937 scala> val vegPackage = packageFood(qingcai, baicai, huanggua) vegPackage: Array[Vegetable] = Array(Vegetable@319988b0, Vegetable@78aea4b9, Vegetable@47428937)
四、協變和逆變
// Scala的協變和逆變是很是有特點的!徹底解決了Java中的泛型的一大缺憾!
// 舉例來講,Java中,若是有Professional是Master的子類,那麼Card[Professionnal]是否是Card[Master]的子類?答案是:不是。所以對於開發程序形成了不少的麻煩。
// 而Scala中,只要靈活使用協變和逆變,就能夠解決Java泛型的問題。
案例:進入會場
scala> class Master
defined class Master
scala> class Professional extends Master
defined class Professional
//大師以及大師級別如下的名片均可以進入會場
scala> class Card[+T] (val name: String)
defined class Card
scala> val leo = new Card[Master]("leo")
leo: Card[Master] = Card@7c28c1
scala> val jack = new Card[Professional]("jack")
jack: Card[Professional] = Card@54da32dc
scala> def enterMeet(card: Card[Master]) {
| println("welcome to have this meeting")
| }
enterMeet: (card: Card[Master])Unit
scala> enterMeet(leo)
welcome to have this meeting
scala> enterMeet(jack)
welcome to have this meeting
//只要專家級別的名片就能夠進入會場,若是大師級別的過來了,固然能夠了!
scala> class Card[-T](val name: String)
defined class Card
scala> val leo = new Card[Master]("leo")
leo: Card[Master] = Card@15cea7b0
scala> val jack = new Card[Professional]("jack")
jack: Card[Professional] = Card@2a22ad2b
scala> def enterMeet(card: Card[Professional]) {
| println("welcome to have this meeting!")
| }
enterMeet: (card: Card[Professional])Unit
scala> enterMeet(jack)
welcome to have this meeting!
scala> enterMeet(leo)
welcome to have this meeting!
五、Existential Type
// 在Scala裏,有一種特殊的類型參數,就是Existential Type,存在性類型。這種類型務必掌握是什麼意思,由於在spark源碼實在是太常見了!
Array[T] forSome { type T }
Array[_]