一.本章要点

  • 类、特质、方法和函数都可以有类型参数
  • 将类型参数放置在名称之后,以方括号括起来
  • 类型界定的语法为T<:UpperBound、T>:LowerBound、T<%ViewBound、T:ContextBound
  • 可以用类型约束来约束一个方法,比如(implicit ev:T<:<UpperBound)
  • 用+T(协变来表示某个泛型的子类型关系和参数T方向一致,或用-T(逆变)来表示方向相反
  • 协变适用于表示输出的类型参数,比如不可表集合中的元素
  • 逆变适用于表示输入的类型参数,比如函数参数

二.泛型类

  和Java/C++一致,类和特质都可以带类型参数。在类的定义中,可以用类型参数来定义变量、方法参数、以及返回值类型。例:

class Pair[T,S]{val first:T,val secend:S}

三.泛型函数

  函数和方法也可以带类型参数。例:

def getMiddle[T](a:Array[T])=a(a.length/2)

四.类型变量界定

  对类型变量进行限制,例:

//错误
class Pair[T](val first:T,val secend:T)
//不知道first是否有compareTo方法
{def smaller=if(first.compareTo(secend)<0) first else secend
} //解决方法(比较简单,也可以指定一个下界)
class Pair[T<:Comparable[T]](val first:T,val secend:T){
def smaller=if(first.compareTo(secend)<0) first else secend
}  
  

五.视图界定

  ”视图界定“,T<%V要求必须存在一个从T到V的隐式转换,如class Pair[T <% Comparable[T]],<%意味着T可以被隐式转换成Comparable[T]。。。          

六.上下文界定

  格式为T:M,其中M是一个泛型类,要求必须存在一个类型为M[T]的”隐式值“。

    

七.Manifest上下文界定

  要实例化一个泛型的Array[T],需要一个Mainfest[T]对象(要想让基本类型的数组能工作,这是必须的),例:

def makePair(T:Mainfest)(first:T,secend:T){
val r=new Array[T](2);r(0)=first;r(1)=secend;r
}

  注:如果T是Int,希望虚拟机中对应的是一个int[]数组,在Scala中,Array只不过是类库中提供的一个类,编译器并不对它做特殊处理,因此要编写一个泛型函数来构造泛型数组,需要传入Mainfest对象帮忙(因为在虚拟机中,泛型相关的信息是被抹掉的,只会有一个makePair方法,却要处理所有类型T)。

八.多重界定

  类型变量可以同时有上界和下界,写法为T >:Lower <:Upper,不能同时有多个上界或多个下界,但能同时实现多个特质。

  可以有多个视图特质:T%<Comparable[T]<%String

  可以有多个上下文界定:T:Ordering:Mainfest

九.类型约束

  提供的另一种限定类型的方式,总共有三种关系:

    T=:=U

    T<:<U

    T<%<U

  这些约束将会测试T是否等于U,是否是U的子类型,或是否能被视图(隐式)转换为U,要使用这样的约束,需要添加”隐式类型证明参数“。  

  类型参数可在泛型类中定义只能在特定条件下使用的方法,例:

class Pair[T](val first:T,val second:T){
def smaller(implicit ev:T<:<Ordered[T])=
if(first<second) first else second
}

  类型约束的另一个用途是改进类型推断,例:

def firstLast[A,C<:Iterable[A](it:C)=(it.head,it.last)]

//执行,推断出的类型参数[Nothing,List[Int]]不符合[A,C<:Iterable[A]]
firstLast(List(1,2,3))  

十.型变

  例:

def makeFriends(p:Pair[Person])
//如果用Pair[Student]作为参数调用makeFriends在缺省情况下是错误的,尽管Student是Person的子类,但Pair[Student]和Pair[Person]没有任何关系 //想要这样的关系,必须在Pair类中表明
//+号意味着该类型是T协变的(与T按同样的类型型变),即Student是Person的子类型=》Pait[Student]是Pair[Person]的子类型
class Pair[+T](val first:T,val second:T) //另一个方向的型变
trait Friend[-T]{
def befriend(someone:T)}
//可以是逆变的,Student是Person的子类型,Friend[Student]是Friend[Person]的超类型
class Person extends Friends[Person]
class Student extends Person
val susan=new Student
val fred=new Person
makeFriendWith(susan,fred)
//注:在一个泛型的类型声明里面,可以同时使用这两种型变

十一.协变和逆变点

  通常而言,对于某个对象消费的值适用于逆变,而对于它产出的值则适用于协变。

  在Scala中数组是不支持型变的,不能将Array[Student]转换为Array[Person],或者反过来会不安全。。。        

十二.对象不能泛型

  没法给对象添加类型参数,比如可变列表。。。

十三.类型通配符

  在Java中,所有泛型类都是不可变的,可以使用通配符改变它们的类型。

  可以在Scala中使用通配符。。。  

十四.练习

Scala学习十七——类型参数的更多相关文章

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

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

  2. Scala学习教程笔记三之函数式编程、集合操作、模式匹配、类型参数、隐式转换、Actor、

    1:Scala和Java的对比: 1.1:Scala中的函数是Java中完全没有的概念.因为Java是完全面向对象的编程语言,没有任何面向过程编程语言的特性,因此Java中的一等公民是类和对象,而且只 ...

  3. 入门大数据---Scala学习

    Scala是什么? Scala是一种基于函数式编程和面向对象的高级语言.它开发了Spark等大型应用.它和Java有效集成,底层也是支持JVM的. 它有六大特性: 无缝JAVA互操作 Scala在JV ...

  4. Scala学习资源

    Scala学习资源: Scala官方网站:http://www.scala-lang.org/ Scala github:https://github.com/scala/scala Twitter ...

  5. 【Todo】【读书笔记】大数据Spark企业级实战版 & Scala学习

    下了这本<大数据Spark企业级实战版>, 另外还有一本<Spark大数据处理:技术.应用与性能优化(全)> 先看前一篇. 根据书里的前言里面,对于阅读顺序的建议.先看最后的S ...

  6. 机器学习(三)--- scala学习笔记

    Scala是一门多范式的编程语言,一种类似Java的编程语言,设计初衷是实现可伸缩的语言.并集成面向对象编程和函数式编程的各种特性. Spark是UC Berkeley AMP lab所开源的类Had ...

  7. 【Scala】Scala学习资料

    Scala学习资料 java 树形 分类器_百度搜索 决策树分类器-Java实现 - CSDN博客 KNN分类器-Java实现 - CSDN博客 学习:java设计模式—分类 - 飞翔荷兰人 - 博客 ...

  8. Scala学习网址

    scala学习网址为:https://twitter.github.io/scala_school/zh_cn https://www.zhihu.com/question/26707124

  9. Spark之Scala学习

    1. Scala集合学习: http://blog.csdn.net/lyrebing/article/details/20362227 2. scala实现kmeans算法 http://www.t ...

随机推荐

  1. IDEA配置Hadoop开发环境&编译运行WordCount程序

    有关hadoop及java安装配置请见:https://www.cnblogs.com/lxc1910/p/11734477.html 1.新建Java project: 选择合适的jdk,如图所示: ...

  2. 【Linux】安装 node.js

    1.在 linux 上安装 node.js 有几种方式,这里 教的是最简单的一种,因为其他都比较坑. 2.先去 node.js 官网 获取到已经编译好的安装包的地址, 3.使用 wget 去下载上面获 ...

  3. windows工程总结

    1.win32控制台console程序 运行在MS-DOS环境中的程序.控制台应用程序通常没有可视化的界面,只是通过字符串来显示或者监控程序.控制台程序常常被应用在测试.监控等用途,用户往往只关心数据 ...

  4. Swagger下载的zip文件无法打开,而且大小比直接下载的要大

    以前写的一个rest提供的是浏览器下载zip包的功能,前端界面调用rest可以正常地下载. 今天使用Swagger来调试下载功能时,发现下载的zip包打不开,而且大小也比直接在浏览器中输入rest地址 ...

  5. 使用XCode7打包动态库(Framework)

    iOS中的静态库和动态库 概念 静态库(Static Library)以 .a 为后缀,它是你的源码的实现.m文件编译而成的二进制文件集合,需要配合上暴漏的.h文件使用,它在引用链接时拷贝至可执行文件 ...

  6. CockroachDB学习笔记——[译]Cgo的成本与复杂性

    原文链接:https://www.cockroachlabs.com/blog/the-cost-and-complexity-of-cgo/ 原作者:Tobias Schottdorf 原文日期:D ...

  7. STM32第二章I/O端口应用

    STM32F10xxx系列中,有7个I/O端口,每个端口有两个32位配置寄存器(GPIOx_CRL,GPIOx_CRH),两个32位数据寄存器(GPIOx_IDR和GPIOx_ODR),一个32位置位 ...

  8. 4.git的基本命令

    版本库 index 暂存区,HEAD 将来1.0,2.0的指向  多次add,一次commit 每次commit一次,head就指向了最新的版本.head是回退版本的时候会用到 一般有开发的分支,ma ...

  9. 【转】TCP/IP网络协议各层首部

    ​ 数据包封装流程(逐层封装,逐层解封) 二层帧(二层帧中目的地址6个字节,源地址6个字节,长度/类型2个字节,二层帧共18个字节) ip头部(ip头部20字节) tcp头部(tcp头部20个字节): ...

  10. Leetcode之分治法专题-654. 最大二叉树(Maximum Binary Tree)

    Leetcode之分治法专题-654. 最大二叉树(Maximum Binary Tree) 给定一个不含重复元素的整数数组.一个以此数组构建的最大二叉树定义如下: 二叉树的根是数组中的最大元素. 左 ...