1. 泛型
  2. 类型边界
  3. 视图界定
  4. 逆变和协变
  5. 上下文界定
  6. 源代码

1.泛型

泛型用于指定方法或类可以接受任意类型参数,参数在实际使用时才被确定,泛型可以有效地增强程序的适用性,

使用泛型可以使得类或方法具有更强的通用性。

在Scala中用方括号来定义类型参数,即用[]表示,

如 class Pair[T, S](val first, val)

以上将定义一个带有两个类型参数T和S的类,带有类型参数的类是泛型的。如果把类型参数替换成实际的类型将得到普通的类。

*简单理解就是类型或者方法后面加个中括号就表示是泛型了,它可以放入任何类型,在实际实例化的时候指定具体的类型。*

2.类型边界

上边界:表达了泛型的类型必须是某种类型或者某种类的子类,语法为`<:`,例如T <: AnyVal表示泛型T的类型的最顶层类是AnyVal。

下边界:表达了泛型的类型必须是某种类型或者某种类的父类,语法为`>:`,例如T >: S表示泛型T的类型必须是S的超类,下界的作用主要是保证类型安全。

3.视图界定

如果希望类型变量界定能跨越类继承层次结构时,可以使用视图界定来实现的,

其后面的原理是通过隐式转换来实现。视图界定利用<%符号来实现,例如后面的例子[T <% Person],

T是Person继承的或者是能变成Person。

4.逆变和协变

逆变和协变最容易理解的便是用List来理解。

协变定义形式如:trait List[+T] {} 。当类型S是类型A的子类型时,则List[S]也可以认为是List[A}的子类型,

即List[S]可以泛化为List[A]。

逆变定义形式如:trait List[-T] {}

当类型S是类型A的子类型,则Queue[A]反过来可以认为是Queue[S}的子类型。

5.上下文界定

上下文界定的类型参数形式为T:M的形式,其中M是一个泛型,这种形式要求存在一个M[T]类型的隐式值。

6.源代码

  1. package com.dtspark.scala.basics
  2.  
  3. /**
  4.  
  5. * Scala类型系统编程实战:
  6.  
  7. * 1,Scala的类和方法、函数都可以是泛型,在Spark源码中可以到处看到类和方法的泛型,在实际实例化的时候指定具体
  8.  
  9. * 的类型,例如Spark最核心、最基础、最重要的抽象数据结构RDD里面关于RDD的类的定义是泛型的,RDD的几乎所有方法
  10.  
  11. * 的定义也都是泛型的,之所以这么做,是因为RDD会派生很多子类,通过子类适配了各种不同的数据源以及业务逻辑操作;
  12.  
  13. * 2, 关于对类型边界的限定,分为上边界和下边界:
  14.  
  15. * 上边界:表达了泛型的类型必须是某种类型或者某种类的子类,语法为<:,这里的一个新的现象是对类型进行限定;
  16.  
  17. * 下边界:表达了泛型的类型必须是某种类型或者某种类的父类,语法为>:;
  18.  
  19. * 3, View Bounds,可以进行某种神秘的转换,把你的类型可以在没有知觉的情况下转换成为目标类型,其实你可以认为 View Bounds是
  20.  
  21. * 上边界和下边界的加强补充版本,例如在SparkContext这个Spark的核心类中有T <% Writable方式的代码,这个代码所表达的是
  22.  
  23. * T必须是Writable类型的,但是T有没有直接继承自Writable接口,此时就需要通过“implicit”的方式来实现这个功能;
  24.  
  25. * 4, T: ClassTag,例如Spark源码中的RDD class RDD[T: ClassTag] 这个其实也是一种类型转换系统,只是在编译的时候类型信息不够,
  26.  
  27. * 需要借助于JVM的runtime来通过运行时信息获得完整的类型信息,这在Spark中是非常重要的,因为Spark的程序的编程和运行是区分了
  28.  
  29. * Driver和Executor的,只有在运行的时候才知道完整的类型信息。
  30.  
  31. * 5, 逆变和协变;-T和+T
  32.  
  33. * 6, Conext Bounds,T: Ordering这种语法必须能够编程Ordering[T]这种方式;
  34.  
  35. */
  36.  
  37. class Engineer
  38.  
  39. class Expert extends Engineer
  40.  
  41. //class Meeting[-T]
  42.  
  43. class Meeting[+T]
  44.  
  45. class Animal[T](val species: T) {
  46.  
  47. def getAnimal(specie: T): T = species
  48.  
  49. }
  50.  
  51. class Maximum[T: Ordering](val x: T, val y: T) {
  52.  
  53. def bigger(implicit ord: Ordering[T]) = {
  54.  
  55. if (ord.compare(x, y) > 0) x else y
  56.  
  57. }
  58.  
  59. }
  60.  
  61. object HelloScalaTypeSystem {
  62.  
  63. def main(args: Array[String]): Unit = {
  64.  
  65. println("=============上界===================")
  66.  
  67. //创建Person,Worker两对象,从[T <: Person]来看要传入的参数是Person的本类或子类
  68.  
  69. val p = new Person("Scala")
  70.  
  71. val w = new Worker("Spark")
  72.  
  73. //这里传入的参数满足要求,故能直接调用comunicate
  74.  
  75. new Club1(p, w).comunicate
  76.  
  77. println("=============视图界定===================")
  78.  
  79. //Person,Worker是有继承结构的,而Dog狗与人是没有的,但是又想使用comunicate方法,怎么办?
  80.  
  81. //答案就是让狗与人隐式的发生关系让狗可以变成人!
  82.  
  83. val dog = new Dog("dahuang")
  84.  
  85. //看见Club2[T <% Person]可知,传入的参数要是人(有继承结构)或者能变成人,
  86.  
  87. //当传入狗时,会去找有没有狗变成人的方法
  88.  
  89. implicit def dog2Person(dog: Dog) = new Person(dog.name)//找到了
  90.  
  91. new Club2[Person](w, dog).comunicate//满足了要求,可以调用comunicate
  92.  
  93. println("=============协变===================")
  94.  
  95. val e = new Meeting[Engineer]
  96.  
  97. participateMeeting(e)
  98.  
  99. val expert = new Meeting[Expert]
  100.  
  101. participateMeeting(expert)
  102.  
  103. println("=============上下文界定===================")
  104.  
  105. //因为[T: Ordering],所以传入的参数为Ordering[T],是可以比较的,所以调用
  106.  
  107. //bigger(implicit ord: Ordering[T])方法,而方法参数是隐式参数就可以直接运行方法体内容,
  108.  
  109. //由于存在Ordering[T],所以有compare方法,直接调用,返回x或y
  110.  
  111. println(new Maximum("Scala", "Java").bigger)
  112.  
  113. }
  114.  
  115. /**
  116.  
  117. * 传入参数类型为Meeting[Engineer],而class Meeting[+T],所以传入的参数可以是有继承结构的参数
  118.  
  119. */
  120.  
  121. def participateMeeting(meeting: Meeting[Engineer]) {
  122.  
  123. println("Welcome")
  124.  
  125. }
  126.  
  127. class Person(val name: String) {
  128.  
  129. def talk(person: Person) {
  130.  
  131. println(this.name + " : " + person.name)
  132.  
  133. }
  134.  
  135. }
  136.  
  137. class Worker(name: String) extends Person(name)
  138.  
  139. class Dog(val name: String)
  140.  
  141. class Club1[T <: Person](p1: T, p2: T){
  142.  
  143. def comunicate = p1.talk(p2)
  144.  
  145. }
  146.  
  147. class Club2[T <% Person](p1: T, p2: T) {
  148.  
  149. def comunicate = p1.talk(p2)
  150.  
  151. }
  152.  
  153. }

Scala之类型参数和对象的更多相关文章

  1. Scala 编程---类和对象

    类是对象的蓝图.一旦你定义了类,你就可以用关键字new从类的蓝图里创建对象.比方说,如果给出了类的定义: class ChecksumAccumulator { // class definition ...

  2. Scala:类,对象和特征(接口)

    http://blog.csdn.net/pipisorry/article/details/52902609 Scala类和对象 类是对象的抽象,而对象是类的具体实例.类是抽象的,不占用内存,而对象 ...

  3. scala学习-类与对象

    类 / 对象 [<快学Scala>笔记] 一.类 1.Scala中的类是公有可见性的,且多个类可以包含在同一个源文件中: class Counter{ private var value ...

  4. 快学Scala 第6章 对象 - 练习

    1. 编写一个Conversions对象,加入inchesToCentimeters.gallonsToLiters和milesToKilometers方法. object Conversions { ...

  5. Scala学习笔记——函数式对象

    用创建一个函数式对象(类Rational)的过程来说明 类Rational是一种表示有理数(Rational number)的类 package com.scala.first /** * Creat ...

  6. Scala学习之路 (六)Scala的类、对象、继承、特质

    一.类 1.类的定义 scala语言中没有static成员存在,但是scala允许以某种方式去使用static成员这个就是伴生机制,所谓伴生,就是在语言层面上,把static成员和非static成员用 ...

  7. scala中json与对象的转换

    遇到的问题 因为要把spark从es读出来的json数据转换为对象,开始想用case class定义类型,通过fastjson做转换.如下 case class Book (author: Strin ...

  8. scala actor编程之对象传递

    scala 最吸引人的一点就是actor并发编程了.但是纵观scala官方文档,baidu文档,IBM文档都写的通过字符串传呀传,如果用作actor编程说明当然没有问题.但是在正式开放中,光传字符串就 ...

  9. Scala学习笔记(6)对象

    1.单例对象.Scala没有静态方法或字段,可以使用object这个语法结构来达到同样的目的.对象定义了单个实例,包含了你想要的特性. object Accounts{ def newUniqueNu ...

随机推荐

  1. Java NIO入门(二):缓冲区内部细节

    Java NIO 入门(二)缓冲区内部细节 概述 本文将介绍 NIO 中两个重要的缓冲区组件:状态变量和访问方法 (accessor). 状态变量是前一文中提到的"内部统计机制"的 ...

  2. ELK 信息统计分析-1

    Aggregations 格式如下: "aggregations"{ //可以简写为aggs "<aggregation_name>":{ //名称 ...

  3. Linux 安装 redis

      环境:centos7 参考:http://blog.csdn.net/lk10207160511/article/details/50364088 步骤如下: 安装redis: 打开终端 输入 s ...

  4. 【ubuntu】中文输入法安装二三事

    本来很愉快地刷着JS程序,很有感慨啊,想写篇博客记一下学习笔记,结果忘记了博客账号,后来通过邮箱找回了之后想要开始写..发现ubuntu的中文输入法不能用啊(其实不是不能用,就是小白没搞清楚状况,双系 ...

  5. c#实现验证码功能

    一.验证码简介 验证码功能一般是用于防止批量注册的,不少网站为了防止用户利用机器人自动注册.登录.灌水,都采用了验证码技术.所谓验证码,就是将一串随机产生的数字或字母或符号或文字,生成一幅图片, 图片 ...

  6. NPOI 读取excel到DataTable 读取隐藏列 读取公式列

    处理思路: 1.打开excel 用NPOI进行读取: 2.读取第一个Sheet: 读取过程中: a.先设置相应列 不隐藏 b.读取Cell时 先判断是否的包含公式 相应代码如下: public sta ...

  7. zookeeper适用场景:zookeeper解决了哪些问题

    问题导读:1.master挂机,传统做法备份必然是以前数据,该如何保证挂机数据与备份数据一致?2.分布式系统如何实现对同一资源的访问,保证数据的强一致性?3.集群中的worker挂了,传统做法是什么? ...

  8. [麦先生]LINUX常用命令总结

    在系统的学习了如何搭建和利用LINUX进行开发后,我利用xMind这一个强大的bug级软件制作了LINUX常见操作命令汇总,但是由于博客园并不支持xMind格式文件的上传,我只能将其做成图片进行分解上 ...

  9. 边工作边刷题:70天一遍leetcode: day 73

    Read N Characters Given Read4 I/II 要点:这题的要点就是搞清楚几个变量的内在逻辑:只有buffer是整4 bytes的.而client要读的bytes(需求)和实际上 ...

  10. HTML5本地存储localStorage与sessionStorage

    在最近的项目中用到了html5的本地存储,下面总结一下. 1.html5几种存储形式 本地存储(localStorage && sessionStorage) 离线缓存(applica ...