介绍

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

知识点

1、泛型类(案例:新生报到)

2、泛型函数(案例:卡片售卖机)

3、上边界Bounds(案例:在派对上交朋友)

4、下边界Bounds(案例:领身份证)

5、View Bounds(案例:跟小狗交朋友)

6、Context Bounds(案例:使用Scala内置的比较器比较大小)

7、Manifest Context Bounds(案例:打包饭菜)

8、协变和逆变(案例:进入会场)

9、Existential Type

泛型类

// 泛型类,顾名思义,其实就是在类的声明中,定义一些泛型类型,然后在类内部,比如field或者method,就可以使用这些泛型类型。

// 使用泛型类,通常是需要对类中的某些成员,比如某些field和method中的参数或变量,进行统一的类型限制,这样可以保证程序更好的健壮性和稳定性。

// 如果不使用泛型进行统一的类型限制,那么在后期程序运行过程中,难免会出现问题,比如传入了不希望的类型,导致程序出问题。

// 在使用类的时候,比如创建类的对象,将类型参数替换为实际的类型,即可。

// Scala自动推断泛型类型特性:直接给使用了泛型类型的field赋值时,Scala会自动进行类型推断。

案例:新生报到,每个学生来自不同的地方,id可能是Int,可能是String

class Student[T](val localId: T) {

def getSchoolId(hukouId: T) = "S-" + hukouId + "-" + localId

}

val leo = new Student[Int](111)

泛型函数

// 泛型函数,与泛型类类似,可以给某个函数在声明时指定泛型类型,然后在函数体内,多个变量或者返回值之间,就可以使用泛型类型进行声明,从而对某个特殊的变量,或者多个变量,进行强制性的类型限制。

// 与泛型类一样,你可以通过给使用了泛型类型的变量传递值来让Scala自动推断泛型的实际类型,也可以在调用函数时,手动指定泛型类型。

案例:卡片售卖机,可以指定卡片的内容,内容可以是String类型或Int类型

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

}

getCard[String]("hello world")

上边界Bounds

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

// Scala的上下边界特性允许泛型类型必须是某个类的子类,或者必须是某个类的父类

案例:在派对上交朋友

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)

}

[T <: Person] :标识这个类型必须是Person 或者Person子类

下边界Bounds

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

案例:领身份证

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.")

}

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

class Party[T <% Person](p1: T, p2: T)

Context Bounds

// Context Bounds是一种特殊的Bounds,它会根据泛型类型的声明,比如“T: 类型”要求必须存在一个类型为“类型[T]”的隐式值。其实个人认为,Context Bounds之所以叫Context,是因为它基于的是一种全局的上下文,需要使用到上下文中的隐式值以及注入。

案例:使用Scala内置的比较器比较大小

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

}

Manifest Context Bounds

// 在Scala中,如果要实例化一个泛型数组,就必须使用Manifest Context Bounds。也就是说,如果数组元素类型为T的话,需要为类或者函数定义[T: Manifest]泛型类型,这样才能实例化Array[T]这种泛型数组。

案例:打包饭菜(一种食品打成一包)

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

}

协变和逆变

// Scala的协变和逆变是非常有特色的!完全解决了Java中的泛型的一大缺憾!

// 举例来说,Java中,如果有Professional是Master的子类,那么Card[Professionnal]是不是Card[Master]的子类?答案是:不是。因此对于开发程序造成了很多的麻烦。

// 而Scala中,只要灵活使用协变和逆变,就可以解决Java泛型的问题。

案例:进入会场

class Master

class Professional extends Master

// 大师以及大师级别以下的名片都可以进入会场

class Card[+T] (val name: String)

def enterMeet(card: Card[Master]) {

println("welcome to have this meeting!")

}

// 只要专家级别的名片就可以进入会场,如果大师级别的过来了,当然可以了!

class Card[-T] (val name: String)

def enterMeet(card: Card[Professional]) {

println("welcome to have this meeting!")

}

Existential Type

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

Array[T] forSome { type T }

Array[_]

Scala 类型参数的更多相关文章

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

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

  2. 11、scala类型参数

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

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

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

  4. 14、Scala类型参数

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

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

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

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

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

  7. 一文详解scala泛型及类型限定

    今天知识星球球友,微信问浪尖了一个spark源码阅读中的类型限定问题.这个在spark源码很多处出现,所以今天浪尖就整理一下scala类型限定的内容.希望对大家有帮助. scala类型参数要点 1. ...

  8. 王家林 大数据Spark超经典视频链接全集[转]

    压缩过的大数据Spark蘑菇云行动前置课程视频百度云分享链接 链接:http://pan.baidu.com/s/1cFqjQu SCALA专辑 Scala深入浅出经典视频 链接:http://pan ...

  9. Scala之类型参数和对象

    泛型 类型边界 视图界定 逆变和协变 上下文界定 源代码 1.泛型 泛型用于指定方法或类可以接受任意类型参数,参数在实际使用时才被确定,泛型可以有效地增强程序的适用性, 使用泛型可以使得类或方法具有更 ...

随机推荐

  1. html5的source元素

    html5的source元素 一.总结 一句话总结: 主要是解决视频播放时候的浏览器的兼容问题 二.html5的source元素 学习要点 掌握source元素的用法 source元素-解决浏览器额兼 ...

  2. cropper手机使用实例

    cropper手机使用实例 一.总结 一句话总结: 启示:还是要多个相关的实例交叉使用,相互印证,查漏补缺,可以更加高效和方便和节约时间 二.Cropper.js从前台到后台的完整实例应用 转自或参考 ...

  3. .net Core 中DateTime在Linux Docker中与Windows时间不一致

    最近写了一个.net core项目,部署到CentOS并在docker上运行的时候,发现DateTime.Now获取的时间与Windows不一致(定时执行的任务,晚了8个小时),在Windows中可以 ...

  4. Robot Framework安装使用

    关于robotframework环境搭建安装请参考 另外一篇博文:Robot Framework的环境搭建(就是一些库文件的安装) 项目基本流程: 1.创建项目New Project----选择dir ...

  5. rapidjson的简单使用(转)

    rapidjson的简单使用 C++ rapidjson 基础入门 rapidjson图文讲解

  6. Java回调机制在RPC框架中的应用示例

    完整源码: https://gitee.com/shiyanjun/x-callback-demo 应用场景描述: 服务提供者在项目启动时,创建并启动一个TCP服务器,然后将自己提供的所有服务注册到注 ...

  7. Centos7搭建OpenNebula云平台

    OpenNebula概述 OpenNebula是专门为云计算打造的开源系统,用户可以使用Xen.KVM.VMware等虚拟化软件一起打造企业云.利用OpenNebula可以轻松构建私有云.混合云.公开 ...

  8. pytorch Containers的Module部分

    参考:https://pytorch.org/docs/stable/nn.html Containers Module CLASS torch.nn.Module 所有神经网络模块的基类 你定义的模 ...

  9. ROS tf基础使用知识

    博客参考:https://www.ncnynl.com/archives/201702/1306.html ROS与C++入门教程-tf-坐标变换 说明: 介绍在c++实现TF的坐标变换 概念: Co ...

  10. Java8的时间日期API

    原先的时间 api  大部分已经过时了 Date构造器 需要传入年月日  但是对时间的加减操作比较麻烦 Calenda  加减比较方便 使用 LocalDate. LocalTime. LocalDa ...