一、类型参数1

1、介绍

类型参数是什么?类型参数其实就类似于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源码。

2、泛型类

// 泛型类,顾名思义,其实就是在类的声明中,定义一些泛型类型,然后在类内部,比如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

3、泛型函数

// 泛型函数,与泛型类类似,可以给某个函数在声明时指定泛型类型,然后在函数体内,多个变量或者返回值之间,就可以使用泛型类型进行声明,从而对某个特殊的
变量,或者多个变量,进行强制性的类型限制。
// 与泛型类一样,你可以通过给使用了泛型类型的变量传递值来让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

4、上边界Bounds

// 在指定泛型类型的时候,有时,我们需要对泛型类型的范围进行界定,而不是可以是任意的类型。比如,我们可能要求某个泛型类型,它就必须是某个类的子类,
这样在程序中就可以放心地调用泛型类型继承的父类的方法,程序才能正常的使用和运行。此时就可以使用上下边界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)
^

5、下边界Bounds

// 除了指定泛型类型的上边界,还可以指定下边界,即指定泛型类型必须是某个类的父类

案例:领身份证
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

1、View Bounds

// 上下边界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

2、Context Bounds

// 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

3、Manifest Context Bounds

// 在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)

4、协变和逆变

// 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!

5、Existential Type

// 在Scala里,有一种特殊的类型参数,就是Existential Type,存在性类型。这种类型务必掌握是什么意思,因为在spark源码实在是太常见了!

Array[T] forSome { type T }
Array[_]

11、scala类型参数的更多相关文章

  1. Scala类型参数中协变(+)、逆变(-)、类型上界(<:)和类型下界(>:)的使用

    转自:http://fineqtbull.iteye.com/blog/477994#bc2364938 有位je上的同学来短信向我问起了Scala类型参数中协变.逆变.类型上界和类型下界的使用方法和 ...

  2. Scala实战高手****第15课:Scala类型参数编程实战及Spark源码鉴赏

    1.Scala的类和方法.函数都可以是泛型 2.上界:表示泛型的类型必须是某种类型或者其类型的子类,语法:<: ,对类型进行限定 3.下界:表示泛型的类型必须是某种类型或者其类型的父类,语法:& ...

  3. 11. Scala数据结构(下)-集合操作

    11.1 集合元素的映射-map映射操作 11.1.1 看一个实际需求 要求:请将List(3,5,8)中所有的元素都*2,将其结果放到一个新的集合中返回,即返回一个新的List(6,10,16),请 ...

  4. Scala 类型参数

    介绍 类型参数是什么?类型参数其实就类似于Java中的泛型.先说说Java中的泛型是什么,比如我们有List a = new ArrayList(),接着a.add(1),没问题,a.add(&quo ...

  5. 14、Scala类型参数

    1.泛型类 2.泛型函数 3.上边界Bounds 4.下边界Bounds 5.View Bounds 6.Context Bounds 7.Manifest Context Bounds 8.协变和逆 ...

  6. Scala类型参数(泛型)与隐式转换

    package com.yz9 import org.junit.Test import scala.collection.mutable.ListBuffer class test { @Test ...

  7. scala学习笔记-类型参数中协变(+)、逆变(-)、类型上界(<:)和类型下界(>:)的使用

    转载自  fineqtbull   http://fineqtbull.iteye.com/blog/477994 有位je上的同学来短信向我问起了Scala类型参数中协变.逆变.类型上界和类型下界的 ...

  8. 了解Scala 宏

    前情回顾 了解Scala反射介绍了反射的基本概念以及运行时反射的用法, 同时简单的介绍了一下编译原理知识, 其中我感觉最为绕的地方, 就属泛型的几种使用方式了. 而最抽象的概念, 就是对于符号和抽象树 ...

  9. 一篇入门 — Scala 宏

    前情回顾 上一节, 我简单的说了一下反射的基本概念以及运行时反射的用法, 同时简单的介绍了一下编译原理知识, 其中我感觉最为绕的地方, 就属泛型的几种使用方式了. 而最抽象的概念, 就是对于符号和抽象 ...

随机推荐

  1. 【leetcode刷题笔记】Edit Distance

    Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2 ...

  2. B表中的pid对应A表中id,查询A表中数据,根据b表中对应a表中该id的数据数目排序

    B表中的pid对应A表中id,查询A表中数据,根据b表中对应a表中该id的数据数目排序 select a.*,count(*) as c from a left join b on a.id=b.ai ...

  3. 算法思考: poj 1969 Count on Canton

                                      A - Count on Canton Time Limit:1000MS     Memory Limit:30000KB     ...

  4. java入门了解11

    1.码表 (一)码表种类 ASCII:美国标准信息交换码,用一个字节的7位可以表示 ISO8859-1:拉丁码表.欧洲码表,用一个字节的8位表示,对ASCII没用到空间补充了自己特有的 GB2312: ...

  5. 大话设计模式--组合模式 Composite -- C++实现实例

    1. 组合模式: 将对象组合成树形结构以表示"部分--整体"的层次结构,组合模式使用户对单个对象和组合对象的使用具有一致性. 需求中是体现部分与整体层次的结构时,希望用户可以忽略组 ...

  6. User Agent注入攻击及防御

    CloudFlare公司经常会收到客户询问为什么他们的一些请求会被 CloudFlare WAF屏蔽.最近,一位客户就提出他不能理解为什么一个访问他主页简单的 GET 请求会被 WAF 屏蔽. 下面是 ...

  7. How to handle Imbalanced Classification Problems in machine learning?

    How to handle Imbalanced Classification Problems in machine learning? from:https://www.analyticsvidh ...

  8. BEC listen and translation exercise 46

    录音文件 https://pan.baidu.com/s/1qYYZGWO The process of learning and exploring a subject can lead to a ...

  9. hdu4699 Editor(双向链表或双栈对弹)

    本题就是两个要点: 1.数据结构的设计.显然可以使用双向链表来做,但是写双向链表的代码复杂度高.其实更好的方法是使用两个对弹的栈来做,而且没必要用STL的栈,就自己开两个数组简单搞一下就好了. 2.最 ...

  10. 多线程编程-pthread 未定义的引用

    多线程编程时用到函数库 pthread.h ,但是该函数库不是linux默认的函数库,所以编译c文件时,需要在目标代码文件后加上 -lpthread参数. 1.未加上 -lpthread 编译时,报错 ...