深圳大数据学习:泛型--【千锋】

深圳大数据学习: 泛型–【千锋】

带有一个或多个类型参数的类是泛型的。

泛型类的定义:

  // 带有类型参数 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

8.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
}

8.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)
}

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

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

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

   }

}

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

  }

}

 

    原文作者:andy888168
    原文地址: http://blog.itpub.net/69947096/viewspace-2660984/
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞