好程序员大数据学习路线分享Scala系列之泛型

好程序员大数据学习路线分享Scala系列之泛型,带有一个或多个类型参数的类是泛型的。

泛型类的定义:

//带有类型参数A的类定义
class Stack[A] {
private var elements: List[A] = Nil
//泛型方法
def push(x: A) { elements = x :: elements }
def peek: A = elements.head
def pop(): A = {
val currentTop = peek
elements = elements.tail
currentTop
}
}

泛型类的使用,用具体的类型代替类型参数A。

val stack = new Stack[Int]
stack.push(1)
stack.push(2)
println(stack.pop) // prints 2
println(stack.pop) // prints 1

1.协变
定义一个类型List[+A],如果A是协变的,意思是:对类型A和B,A是B的子类型,那么List[A]是List[B]的子类型。

abstract class Animal {
def name: String
}
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal

Scala标准库有一个泛型类sealed abstract class List[+A],因为其中的类型参数是协变的,那么下面的程序调用时成功的。

object CovarianceTest extends App {
//定义参数类型List[Animal]
def printAnimalNames(animals: List[Animal]): Unit = {
animals.foreach { animal =>
println(animal.name)
}
}

val cats: List[Cat] = List(Cat("Whiskers"), Cat("Tom"))
val dogs: List[Dog] = List(Dog("Fido"), Dog("Rex"))
//传入参数类型为List[Cat]
printAnimalNames(cats)
// Whiskers
// Tom
//传入参数类型为List[Dog]
printAnimalNames(dogs)
// Fido
// Rex
}

2.逆变
定义一个类型Writer[-A],如果A是逆变的,意思是:对类型A和B,A是B的子类型,那么Writer[B]是Writer[A]的子类型。

abstract class Animal {
def name: String
}
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal

定义对应上述类进行操作的打印信息类

abstract class Printer[-A] {
def print(value: A): Unit
}
class AnimalPrinter extends Printer[Animal] {
def print(animal: Animal): Unit =
println("The animal‘s name is: " + animal.name)
}

class CatPrinter extends Printer[Cat] {
def print(cat: Cat): Unit =
println("The cat‘s name is: " + cat.name)
}

逆变的测试

object ContravarianceTest extends App {
val myCat: Cat = Cat("Boots")

//定义参数类型为Printer[Cat]
def printMyCat(printer: Printer[Cat]): Unit = {
printer.print(myCat)
}

val catPrinter: Printer[Cat] = new CatPrinter
val animalPrinter: Printer[Animal] = new AnimalPrinter

printMyCat(catPrinter)
//可以传入参数类型为Printer[Animal]
printMyCat(animalPrinter)
}

3.上界
上界定义: T <: A ,表示类型变量T 必须是 类型A 子类

abstract class Animal {
def name: String
}

abstract class Pet extends Animal {}

class Cat extends Pet {
override def name: String = "Cat"
}

class Dog extends Pet {
override def name: String = "Dog"
}

class Lion extends Animal {
override def name: String = "Lion"
}
//参数类型须是Pet类型的子类
class PetContainer[P <: Pet](p: P) {
def pet: P = p
}
//Dog是Pet类型的子类
val dogContainer = new PetContainer[Dog](new Dog)
//Cat是Pet类型的子类
val catContainer = new PetContainer[Cat](new Cat)
//Lion不是Pet类型的子类,编译通不过
// val lionContainer = new PetContainer[Lion](new Lion)

4.下界
语法 B >: A 表示参数类型或抽象类型 B 须是类型A的父类。通常,A是类的类型参数,B是方法的类型参数。

上面这段代码,因为作为协变类型的B,出现在需要逆变类型的函数参数中,导致编译不通过。解决这个问题,就需要用到下界的概念。

trait Node[+B] {
def prepend[U >: B](elem: U): Node[U]
}

case class ListNode[+B](h: B, t: Node[B]) extends Node[B] {
def prepend[U >: B](elem: U): ListNode[U] = ListNode(elem, this)
def head: B = h
def tail: Node[B] = t
}

case class Nil[+B]() extends Node[B] {
def prepend[U >: B](elem: U): ListNode[U] = ListNode(elem, this)
}

测试

trait Bird
case class AfricanSwallow() extends Bird
case class EuropeanSwallow() extends Bird

val africanSwallowList= ListNode[AfricanSwallow](AfricanSwallow(), Nil())
val birdList: Node[Bird] = africanSwallowList
birdList.prepend(new EuropeanSwallow)

5 视界(view bounds)
注意:已过时,了解即可

视界定义: A <% B ,表示类型变量A 必须是 类型B`的子类,或者A能够隐式转换到B

class Pair_Int[T <% Comparable[T]] (val first: T, val second: T){
def bigger = if(first.compareTo(second) > 0) first else second
}

class Pair_Better[T <% Ordered[T]](val first: T, val second: T){
def smaller = if(first < second) first else second
}
object View_Bound {

def main(args: Array[String]) {
// 因为Pair[String] 是Comparable[T]的子类型, 所以String有compareTo方法
val pair = new Pair_Int("Spark", "Hadoop");
println(pair.bigger)

/**
  * Scala语言里 Int类型没有实现Comparable;
  * 那么该如何解决这个问题那;
  * 在scala里 RichInt实现了Comparable, 如果我们把int转换为RichInt类型就可以这样实例化了.
  * 在scala里 <% 就起这个作用, 需要修改Pair里的 <: 为<% 把T类型隐身转换为Comparable[Int]
  * String可以被转换为RichString. 而RichString是Ordered[String] 的子类.
  */
val pair_int = new Pair_Int(3 ,45)
println(pair_int.bigger)

val pair_better = new Pair_Better(39 ,5)
println(pair_better.smaller)

}

}

6 上下文界定(context bounds)
上下文界定的形式为 T : M, 其中M 必须为泛型类, 必须存在一个M[T]的隐式值.

class Pair_Context[T : Ordering](val first: T, val second: T){
def smaller(implicit ord: Ordering[T]) =
if(ord.compare(first, second) < 0) first else second
}

object Context_Bound {

def main(args: Array[String]) {

val pair = new Pair_Context("Spark", "Hadoop")
println(pair.smaller)

val int = new Pair_Context(3, 5)
println(int.smaller)

}

}

原文地址:https://blog.51cto.com/14479068/2441202

时间: 2024-10-04 03:08:11

好程序员大数据学习路线分享Scala系列之泛型的相关文章

好程序员大数据学习路线分享Scala系列之集合操作函数

好程序员大数据学习路线继续为大家分享Scala系列之集合操作函数4.6 集合的重要函数4.6.1sum/max/min/count在序列中查找最大或最小值是一个极常见的需求,如下:val numbers = Seq(11, 2, 5, 1, 6, 3, 9) numbers.max //11 numbers.min //1 更高级的例子,其中包含一个书的序列case class Book(title: String, pages: Int) val books = Seq( Book("Futu

好程序员大数据学习路线分享Scala分支和循环

好程序员大数据学习路线分享Scala分支和循环3.3. 条件表达式表达式:一个具有执行结果的代码块.结果是具体的值或者() 表达式的思考方式:以表达式为中心的编程思想 1.表达式和语句的区别:表达式有返回值,语句被执行.表达式一般是一个语句块,执行后,返回一个值 2.不使用return语句,最后一个表达式即返回值 if/else表达式有值,这个值就是跟在if或者else之后的表达式的值 object ConditionDemo {def main(args: Array[String]){var

好程序员大数据学习路线分享scala单列和伴生对象

scala单例 object SingletonDemo { ??def main(args: Array[String]): Unit = { ????val s = SessionFactory ????println(s.getSession) ????println(s.getSession.size) ?//.size得到几个session对象 ??} } object SessionFactory{ ??println("SessionFactory 被执行了") ?? ?

好程序员大数据学习路线分享hive的运行方式

好程序员大数据学习路线分享hive的运行方式,hive的属性设置: 1.在cli端设置 (只针对当前的session) 3.在java代码中设置 (当前连接) 2.在配置文件中设置 (所有session有效) 设置属性的优先级依次降低. cli端只能设置非hive启动需要的属性.(log属性,元数据连接属性) 查找所有属性: hive>set; 查看当前属性的值:通常是hadoop hive> set -v; 模糊查找属性: hive -S -e "set" | grep

好程序员大数据学习路线分享高阶函数

好程序员大数据学习路线分享高阶函数,我们通常将可以做为参数传递到方法中的表达式叫做函数 高阶函数包含:作为值的函数.匿名函数.闭包.柯里化等等. 定义函数时格式:val 变量名 =?(输入参数类型和个数)?=>?函数实现和返回值类型和个数 "="表示将函数赋给一个变量 "=>"左面表示输入参数名称.类型和个数,右边表示函数的实现和返回值类型和参数个数 作为值的函数 定义函数 scala> val func = (x:Int) => x * x

好程序员大数据学习路线分享MAPREDUCE

好程序员大数据学习路线分享MAPREDUCE,需求:统计大量的文本文件中的单词出现的次数 1)整个运算需要分阶段 阶段一:并行局部运算 阶段二 :汇总处理,不同的阶段需要开发不同的程序 2)阶段之间的调用 3)业务程序(task程序)如何并发到集群并启动程序 4)如何监控task程序的运行状态,如何处理异常 ::这些问题是开发分布式程序都会面临的问题,完全可以封装成框架::MR 的结构 一个完整的MapReduce运行时有三类实例进程: 1)MRAppMaster : 负责整个程序的过程调度和状

好程序员大数据学习路线分享Hadoop阶段的高可用配置

大数据学习路线分享Hadoop阶段的高可用配置,什么是Hadoop的HA机制 Ha机制即Hadoop的高可用(7*24小时不中断服务) 正式引入HA机制是从hadoop2.0开始,之前的版本中没有HA机制 hadoop-ha严格来说应该分成各个组件的HA机制--HDFS的HA.YARN的HA HDFS的HA机制详解HDFS 的HA主要是通过双namenode协调工作实现 双namenode协调工作的要点:A.元数据管理方式需要改变: 内存中各自保存一份元数据 Edits日志只能有一份,只有Act

好程序员大数据学习路线分享HDFS读流程

1.客户端或者用户通过调用FileSystem对象的Open()方法打开需要读取的文件,这时就是HDSF分布式系统所获取的一个对象 2.FileSystem通过远程协议调用NameNode确定文件的前几个Block的位置,对于每一个block,NameNode返回一个含有Block的元数据信息,接下来DataNode按照上面定义的距离(offSet偏移量)进行排序,如果Client本身即是一个DataNode,那么就会优先从本地DataNode节点读取数据. HDFS完成上面的工作之后返回一个F

好程序员大数据学习路线Hadoop学习干货分享

好程序员大数据学习路线Hadoop学习干货分享,Apache Hadoop 为可靠的,可扩展的分布式计算开发开源软件.Apache Hadoop软件库是一个框架,它允许使用简单的编程模型跨计算机群集分布式处理大型数据集(海量的数据).包括这些模块: Hadoop Common:支持其他Hadoop模块的常用工具. Hadoop分布式文件系统(HDFS?):一种分布式文件系统,可提供对应用程序数据的高吞吐量访问. Hadoop YARN:作业调度和集群资源管理的框架. Hadoop MapRedu