Spark基础-scala学习(七、类型参数)
类型参数是什么
- 类似于java泛型,泛型类
- 泛型函数
- 上边界Bounds
- 下边界
- View Bounds
- Context Bounds
- Manifest Context Bounds
- 协变和逆变
- Existential Type
泛型类
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Student[T](val localId:T){
def getSchoolId(hukouId:T) = "S-"+hukouId+"-"+localId
}
// Exiting paste mode, now interpreting.
defined class Student
scala> val s = new Student[Int](11)
s: Student[Int] = Student@a451491
scala> s.getSchoolId(234)
res1: String = S-234-11
泛型函数
- 泛型函数,与泛型类类似,可以给某个函数在声明时指定泛型类型,然后在函数体内,多个变量或者返回值之间,就可以使用泛型类型进行声明,从而对某个特殊的变量,或者多个变量,进行强制性的类型限制
- 与泛型类一样,你可以通过使用了泛型类型的变量传递值来让Scala自动推断泛型的实际类型,也可以在调用函数时,手动指定泛型类型
scala> :paste
// Entering paste mode (ctrl-D to finish)
def getCard[T](content:T)={
if(content.isInstanceOf[Int]) "card: 001,"+content
else if(content.isInstanceOf[String]) "card:this is your card, "+content
else "card: "+content
}
// Exiting paste mode, now interpreting.
getCard: [T](content: T)String
scala> getCard[String]("leo")
res2: String = card:this is your card, leo
scala> getCard[Int](123)
res3: String = card: 001,123
上边界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> val p = new Person("Tom")
p: Person = Person@e344f14
scala> val p2 = new Person("leo")
p2: Person = Person@6e96f3cd
scala> p.makeFriends(p2)
Hello,I'm Tom
Hello,I'm leo
scala> val s1 = new Student("Jarry")
s1: Student = Student@58ca1cad
scala> val s2 = new Student("Marry")
s2: Student = Student@64c79b69
scala> val pa = new Party[Student](s1,s2)
pa: Party[Student] = Party@6a28d987
scala> pa.play
Hello,I'm Jarry
Hello,I'm Marry
下边界Bounds
- 除了指定泛型类型的上边界,还可以指定下边界,即指定泛型类型必须是某个类的父类
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Father(val name:String)
class Child(name:String) extends Father(name)
def getIDCard[R >: Child](person:R){
if(person.getClass == classOf[Child]) println("please tell us your parents' names.")
else if(person.getClass == classOf[Father]) println("sign your name for your child's id card.")
else println("sorry,you are not allowed to get id card.")
}
// Exiting paste mode, now interpreting.
defined class Father
defined class Child
getIDCard: [R >: Child](person: R)Unit
scala> val f = new Father("fa")
f: Father = Father@40f40221
scala> val c = new Child("cd")
c: Child = Child@3d44f15d
scala> getIDCard[Father](f)
sign your name for your child's id card.
scala> getIDCard[Child](c)
please tell us your parents' names.
View Bounds
- 上下边界Bounds,虽然可以让一种泛型类型,支持有父子关系的多种类型。但是,在某个类与上下边界Bounds指定的父子类型范围内的类都没有任何关系,则默认是肯定不能接受的
- 然而,View Bounds作为一种上下边界Bounds的加强版,支持可以对类型进行隐式转换,将指定的类型进行隐式转换后,再判断是否在边界指定的类型范围内
- 案例:跟小狗交朋友
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 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
class Party[T <% Person](p1:T,p2:T)
// Exiting paste mode, now interpreting.
<pastie>:23: warning: implicit conversion method dog2person should be enabled
by making the implicit value scala.language.implicitConversions visible.
This can be achieved by adding the import clause 'import scala.language.implicitConversions'
or by setting the compiler option -language:implicitConversions.
See the Scaladoc for value scala.language.implicitConversions for a discussion
why the feature should be explicitly enabled.
implicit def dog2person(dog: Object):Person = if(dog.isInstanceOf[Dog]){val _dog = dog.asInstanceOf[Dog];new Person(_dog.name)} else Nil
^
defined class Person
defined class Student
defined class Dog
dog2person: (dog: Object)Person
defined class Party
scala> val leo = new Student("leo")
leo: Student = Student@5a22eec0
scala> val doggy = new Dog("doggy")
doggy: Dog = Dog@231a08d
scala> val party = new Party(leo,doggy)
party: Party[Object] = Party@7e0cbe79
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 ca = new Calculator[Int](12,23)
ca: Calculator[Int] = Calculator@723c7f2f
scala> ca.max
res8: Int = 23
Manifest Context Bounds
- 在scala中,如果要实例化一个泛型数组,就必须使用Manifest Context Bounds,也就是说,如果数组元素类型为T的话,需要为类或者函数定义[T:Manifest]泛型类型,这样才能实例化Array[T]这种泛型数组
- 案例:打包饭菜(一种食品打成一包)
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Meat(val name:String)
class Vegetable(val name:String)
def packageFood[T:Manifest](food: T*) = {
val foodPackage = new Array[T](food.length)
for(i <- 0 until food.length) foodPackage(i) = food(i)
foodPackage
}
// Exiting paste mode, now interpreting.
defined class Meat
defined class Vegetable
packageFood: [T](food: T*)(implicit evidence$1: Manifest[T])Array[T]
scala> val gongbaojiding = new Meat("gongbaojiding")
gongbaojiding: Meat = Meat@330a0dbb
scala> val shoushibaocai = new Meat("shoushibaocai")
shoushibaocai: Meat = Meat@6e74986c
scala> val meatPackage = packageFood(gongbaojiding,shoushibaocai)
meatPackage: Array[Meat] = Array(Meat@330a0dbb, Meat@6e74986c)
协变和逆变
- scala的协变和逆变完全解决了java中的泛型的一大缺憾
- 举例来说,java中,如果有professional是Master的子类,那么Card(Professionnal)是不是Card(Master)的子类呢?答案是:不是。
- 而scala中,只要灵活使用协变和逆变,就可以解决java泛型的问题
- 案例:进入会场
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Master
class Professional extends Master
//大师以及大师级别以下的名片都可以进入会场
class Card[+T](val name:String)
def enterMeet(card:Card[Master]){
println("Welcome to have this meeting")
}
// Exiting paste mode, now interpreting.
defined class Master
defined class Professional
defined class Card
enterMeet: (card: Card[Master])Unit
scala> val leo = new Card[Master]("leo")
leo: Card[Master] = Card@762637be
scala> val jack = new Card[Professional]("jack")
jack: Card[Professional] = Card@4aa11206
scala> enterMeet(leo)
Welcome to have this meeting
scala> enterMeet(jack)
Welcome to have this meeting
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Card[-T](val name:String)
def enterMeet(card:Card[Professional]){
println("welcome to have this meeting!")
}
// Exiting paste mode, now interpreting.
defined class Card
enterMeet: (card: Card[Professional])Unit
scala> val leo = new Card[Master]("leo")
leo: Card[Master] = Card@3700994c
scala> val jack = new Card[Professional]("jack")
jack: Card[Professional] = Card@62581ef6
scala> enterMeet(leo)
welcome to have this meeting!
scala> enterMeet(jack)
welcome to have this meeting!
Existential Type
- 在scala中,有一种特殊的类型参数,就是Existential Type存在性类型。
Array[T] forSome {type T}
//占位符
Array[_]
Spark基础-scala学习(七、类型参数)的更多相关文章
- Spark基础-scala学习(三、Trait)
面向对象编程之Trait trait基础知识 将trait作为接口使用 在trait中定义具体方法 在trait中定义具体字段 在trait中定义抽象字段 trait高级知识 为实例对象混入trait ...
- Spark基础-scala学习(二、面向对象)
面向对象编程之类 //定义一个简单的类 scala> :paste // Entering paste mode (ctrl-D to finish) //类默认public的 class He ...
- Spark基础-scala学习(八、隐式转换与隐式参数)
大纲 隐式转换 使用隐式转换加强现有类型 导入隐式转换函数 隐式转换的发生时机 隐式参数 隐式转换 要实现隐式转换,只要程序可见的范围内定义隐式转换函数即可.Scala会自动使用隐式转换函数.隐式转换 ...
- Spark基础-scala学习(五、集合)
集合 scala的集合体系结构 List LinkedList Set 集合的函数式编程 函数式编程综合案例:统计多个文本内的单词总数 scala的集合体系结构 scala中的集合体系主要包括:Ite ...
- Spark基础-scala学习(四、函数式编程)
函数式编程 将函数赋值给变量 匿名函数 高阶函数 高级函数的类型推断 scala的常用高阶函数 闭包 sam转换 currying函数 return 将函数赋值给变量 scala中的函数是一等公民,可 ...
- Spark基础-scala学习(一、入门)
Scala解析器的使用 REPL:Read(取值)-> Evaluation(求值)-> Print(打印)->Loop(循环).scala解析器也被称为REPL,会快速编译scal ...
- Spark之Scala学习
1. Scala集合学习: http://blog.csdn.net/lyrebing/article/details/20362227 2. scala实现kmeans算法 http://www.t ...
- Scala学习十七——类型参数
一.本章要点 类.特质.方法和函数都可以有类型参数 将类型参数放置在名称之后,以方括号括起来 类型界定的语法为T<:UpperBound.T>:LowerBound.T<%ViewB ...
- scala学习笔记-类型参数中协变(+)、逆变(-)、类型上界(<:)和类型下界(>:)的使用
转载自 fineqtbull http://fineqtbull.iteye.com/blog/477994 有位je上的同学来短信向我问起了Scala类型参数中协变.逆变.类型上界和类型下界的 ...
随机推荐
- java学习(四)
学号 20189214 <Java程序设计>第四周学习总结 教材学习内容总结 枚举 枚举是JDK1.5版本新增的特性(泛型.For-each等如今被广泛应用的特性也是由JDK1.5时所新增 ...
- vue.js中axios的封装
基于前文所述,axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,它有很多优秀的特性,例如拦截请求和响应.取消请求.转换json.客户端防御XSRF等. 如果还对a ...
- 文件操作命令(replace)
Replace 命令: // 描述: 替换文件. // 语法: REPLACE [drive1:][path1]filename [drive2:][path2] [/A] [/P] [/R] [/W ...
- 本地文件程序脚本上传linux系统中文乱码问题
# 使用notepad++ 编辑器打开,转换一下格式保存,然后上传即可
- mysql第一课,数据库的简单简单操作方法(配图略虐狗)
mysql -u root -p 并输入密码进入mysql管理界面 show databases; 显示数据库列表 use 数据库名; 进入该数据库 show tables;显示表列表 建立新表 添加 ...
- Java:编码与乱码问题
一.为什么要编码? 由于人类的语言太多,因而表示这些语言的符号太多,无法用计算机的一个基本的存储单元----byte来表示,因而必须要经过拆分或一些翻译工作,才能让计算机能理解. byte一个字节即8 ...
- Java程序设计(第二版)复习 第三章
数组的使用 首先定义,然后用new生成数组,最后通过下标访问 定义 此时只是引用还未分配内存空间,需要使用new去分配内存空间,否则是无法被访问的 定义的两种方法:数据类型 数组名[];数据类型 [] ...
- MySQL中 指定字段排序函数field()的用法
MySQL中的field()函数,可以用来对SQL中查询结果集进行指定顺序排序. 函数使用格式如下: order by (str,str1,str2,str3,str4……),str与str1,str ...
- 预装win8的笔记本用第三方分区软件分区后出现0x0000225错误的解决方法/同理win7
最近为采用EFI分区的联想电脑分区,是通过第三方软件进行的,完成后重启,发现系统报错0x0000225,提示插入安装介质修复. 应该是EFI分区导致的 http://zhidao.baidu.com/ ...
- 基于UML的高校教务管理系统的设计与实现
一.基本信息 标题:基于UML的高校教务管理系统的设计与实现 时间:2018 出版源:南昌航空大学 领域分类:教育信息化:教务管理系统:UML:SSH:Oracle 二.研究背景 问题定义:高校教务管 ...