好程序员-千锋教育旗下高端IT职业教育品牌

400-811-9990
我的账户
好程序员

专注高端IT职业培训

亲爱的猿猿,欢迎!

已有账号,请

如尚未注册?

  • 客服QQ
  • 官方微信

    好程序员

    专注高端IT职业培训

[BigData] 好程序员大数据培训分享Scala系列之泛型

[复制链接]
25 0
  好程序员大数据培训分享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
}
//DogPet类型的子类
val dogContainer = new PetContainer[Dog](new Dog)
//CatPet类型的子类
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]的子类型, 所以StringcompareTo方法
    val pair = new Pair_Int("Spark", "Hadoop");
    println(pair.bigger)

    /**
      * Scala语言里 Int类型没有实现Comparable;
      * 那么该如何解决这个问题那;
      * scalaRichInt实现了Comparable, 如果我们把int转换为RichInt类型就可以这样实例化了.
      * scala<% 就起这个作用, 需要修改Pair里的 <: <% T类型隐身转换为Comparable[Int]
      * String可以被转换为RichString. RichStringOrdered[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)

  }

}
好程序员大数据培训官网:http://obomdaqui.com/bigdata.shtml

精彩内容,一键分享给更多人!
收藏
收藏0
转播
转播
分享
淘帖0
支持
支持0
反对
反对0
回复

使用道具 举报

您需要登录后才可以回帖

本版积分规则

关注我们
千锋好程序员

北京校区(总部):北京市海淀区宝盛北里西区28号中关村智诚科创大厦

深圳西部硅谷校区:深圳市宝安区宝安大道5010号深圳西部硅谷B座A区605-619

杭州龙驰智慧谷校区:浙江省杭州市下沙经济技术开发区元成路199号龙驰智慧谷B座7层

郑州校区:郑州市二七区航海中路60号海为科技园C区10层、12层

Copyright 2007-2019 北京千锋互联科技正规体育投注 .All Right

京ICP备12003911号-5 京公安网11010802011455号

请您保持通讯畅通1对1咨询马上开启