zoukankan      html  css  js  c++  java
  • Scala中的泛型

    1. 类型参数可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法  
    2. 类型参数
      1. 调用时不指定[T]:可以通过给泛型声明的变量传递值来让scala自动推断泛型的实际类型;返回的是使表达式编译通过的合适的类型;在编译时不会检查类型是否满足
      2. 调用时指定[T]:可以在函数的调用时候指定泛型的类型;则返回对就必须是T类型;会在编译时检查类型,不满足泛型规则编译不通过

    泛型类

    1. 泛型类:指可以接受类型参数的类。泛型类在集合类中被广泛使用。(如:各种容器类List、Set、Map)
    2. 定义一个泛型类:泛型类使用方括号 [] 来接受类型参数。一个惯例是使用字母 A 作为参数标识符,当然你可以使用任何参数名称。
    3. 泛型类的使用  :要使用一个泛型类,将一个具体类型放到方括号中来代替 A。
    object test{
      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
        }
      }
      // Stack 类的实现中接受类型参数 A。 这表示其内部的列表,var elements: List[A] = Nil,只能够存储类型 A 的元素。
      //方法 def push 只接受类型 A 的实例对象作为参数
      def main(args: Array[String]): Unit = {
        val stack = new Stack[Int]
        stack.push(1)
        stack.push(2)
        println(stack.pop)  // prints 2
        println(stack.pop)  // prints 1
      }
    }

    泛型函数

    1. 泛型函数:指可以接受类型参数的函数
    2. 定义泛型函数:泛型函数使用方括号 [] 来接受类型参数。一个惯例是使用字母 A 作为泛型参数标识符
    3. 泛型类的使用  :要使用一个泛型函数,将一个具体类型放到方括号中来代替 A
    object test2{
      def main(args: Array[String]): Unit = {
        def getfiled[T](content: T) = {
          content match {
            case a:Int =>println("这是Int类型")
            case a:String =>println("这是Stringt类型")
            case _ =>println("这是未知类型")
          }
        }
        getfiled("2")       //通过给泛型声明的变量传递值来让scala自动推断泛型的实际类型。
      }
    }

    上边界

    1. 为什么需要边界:在指定泛型类型的时候,有时,我们需要对泛型的类型的范围进行界定,而不是任意的类型
    2. 上边界:[A<B]
    3. 上边界特性:左边的类型参数A是右边类型B的子类
    4. 作用:我们可能要求某个泛型,它就必须是某个类A的子类,这样在程序中就可以放心地调用A类的方法
      1. 比如:我们并不知道类型T到底有没有compareTo方法,编译报错,所以要使用上边界,是参数类型T的类型是含有compareTo的类或者其子类
      2. 编译报错:class Pair[T](val first:T, val second:T) {def smaller = if (first.compareTo(second)) }   
      3. 编译正确:class Pair[T <: Comparable[T]](val first:T, val second:T) {def smaller = if (first.compareTo(second)) }  
    object test3{
      class Person(val name: String){}
      class Teacher(name:String)
      class Student(name: String) extends Person(name)
      class Play[T <: Person](p: T) {}
    
    
      def main(args: Array[String]): Unit = {
        val wiki=new  Student("Wiki")
        val tom=new Teacher("Tom")
        val play =new Play(wiki) //[Person]可以省略自行推导
        //   val s=new Play(tom) 报错 因为Teacher不是Person子类。这就是上边界
      }
    }

    下边界 

    1. 下边界:[A>B]
    2. 下边界特性:左边的类型参数A是右边类型B父类
    3. 注意:如果是在调用的时候省略了[T],让scala自动去推断,scala会自动向上转型,使编译通过而不会报错(无论参数是什么类型都会编译通过)
    object test4{
      class Father(val name: String)
      class Child(name: String) extends Father(name)
      class Grandson(name: String) extends Child(name)
      class Frind(val name: String)
      class makyFrind[R >: Child](name:R)
      def main(args: Array[String]): Unit = {
        val father=new Father("wiki")
        val child=new Child("wiki")
        val grandson =new Grandson("wiki")
        val frind =new Frind("wiki")
        val makefrind1: makyFrind[Father] = new makyFrind(father)
        val makefrind2: makyFrind[Child] = new makyFrind(child)
        val makefrind3: makyFrind[Object] = new makyFrind(frind)   //不会报错 会自动向上转型
        val makefrind = new makyFrind[Frind](frind) // 编译报错   frind不是child的父类
        val makefrind4: makyFrind[Child] = new makyFrind(grandson)
      }
    }

    视图边界

    1. 视图边界:[A <% B]
    2. 视图边界特性:左边的类型参数A是右边类型B或者是其子类。如果不是,左边类型会使用隐士转换将左边的类型参数A转换为右边类型B或者其子类(前提是隐式转换的方法已经具备)
    object test5{
      class Person( val name: String)
      class Student(name: String) extends Person(name)
      class worker(val name: String)
      class playBall[T <% Person](p1: T, p2: T)  {
        println("这是playBall对象")
      } //<%必须为这个类或子类,不是就隐式转换
    
      implicit def worker2person(obj: Object): Person = {
        obj match {
          case work :worker=>println(work.name+":OK");new Person(work.name)
          case _ =>println("不进行转换");null
        }
      }
      def main(args: Array[String]): Unit = {
        val  work1=new worker("work1")
        val  work2=new worker("work2")
        val  person=new Person("person")
        val  student=new Student("student")
        val playball3  =new playBall[Person](work1,work2)
        println("=============")
        val playball4: playBall[Person] =new playBall[Person](person,work2)
    
        // 在调用的时候加上[T],则返回对就必须是T类型,不加[T],返回的是使表达式编译通过的合适的类型
        //加[T]会在编译时检查类型,不满足泛型规则编译不通过
        //不加[T]会在编译时不会检查类型是否满足,满足泛型规则在运行时检查会报错
        val play3: playBall[worker] =new playBall(work1,work2)
        val play4: playBall[Object] =new playBall(person,work2)
      }
    }

    上下文界定 

    1. 上下文界定:[A:B]
    2. 一个上下文界定相当于一个隐式参数。([A:B]:就相当于一个隐式参数implicit b:B[A])
    3. 如:def foo[A : B](a: A) = g(a) 等价于 def foo[A](a:A)(implicit b:B[A]) = g(a)
      1. 隐式参数的类型是B
      2. foo函数的泛型和隐式参数b的泛型是A
    4. implicitly:用来获取上下文中满足类型要求的隐式值
    object test6{
      class  Stringer[T] {
        def toString(a: T, b: T): Unit = {
          println(s"$a + $b")
        }
      }
      def foo1[T](a: T, b: T)(implicit stringer: Stringer[T])= {
        stringer.toString(a, b)
      }
      // 在方法入参上拿不到关于 Stringer 对象的值,那么我们可以通过 implicitly 这个 标识符 来获取程序上下文中存在的关于Stringer[T]类型的隐式值,
      // 这个 标识符 的作用就在于此,它是自动的去获取到。
      def foo2[T:Stringer](a: T, b: T) = {
        val stringer: Stringer[T] = implicitly[Stringer[T]]
        stringer.toString(a, b)
      }
      def main(args: Array[String]): Unit = {
        implicit val stringer: Stringer[Int] = new Stringer[Int]
        val result1 = foo1(2, 3)
        val result2 = foo2(2, 3)
      }
    }

    Manifest上下文界定 

    1. Manifest上下文界定:[T: Manifest]
    2. 泛型类实例化为一个对象:class Play[T]
      1. 将泛型变成具体的类型;val play1 = new Play[Int]
      2. 将实例化表达式放入[T: Manifest]定义的类或者方法中 :def Pay [T:Manifest] = {val play1 = new Play[T]}
    object test7{
      class Meat(val name: String)
      class Vegetable(val name: String)
      def main(args: Array[String]): Unit = {
        val arr1 = new Array[Int](1)  // 传入具体的类型 
    //    val arr2 = new Array[T](1)  //错误
        def test[T:Manifest]: Unit ={
          val arr3 = new Array[T](1)  //需要泛型数组所在类或者函数定义[T: Manifest]泛型类型
        }
      }
    }

    协变和逆变

    协变

    1. 协变:对于泛型类ClassName[+T] ,如果A是B的子类,那么ClassName[A]是ClassName[B]的子类(泛型类的的关系和类型参数的关系相同)
    /**
      * 如果Father是Son父类,则Person[Father]也是Person[Son]父类,这就是协变
      * []里继承关系:Grandson->Son->Father
      * Person的继承关系Person[Grandson]->Person[Son]->Person[Father]
      */
    object test81{
      class Father
      class Son extends Father
      class Grandson extends Son
      class Person[+T] (val name: String) //+T协变
      def main(args: Array[String]): Unit = {
        def makeMoney(person:Person[Son]) {
          println(s"你是${person.name},你应该去工作赚钱")
        }
        val father = new Person[Father]("father")
        val son = new Person[Son]("儿子")
        val grandson = new Person[Grandson]("孙子")
    //    makeMoney(father) //  父亲老了不需要赚钱
          makeMoney(son)
          makeMoney(grandson)
      }
    }

    逆变

    1. 逆变:对于泛型类ClassName[-T] ,如果A是B的子类,那么ClassName[A]是ClassName[B]的父类(泛型类的的关系和类型参数的关系相反)
    /**
      * 逆变是Person将[]里面的继承关系逆转过来
      * []里继承关系:Grandson->Son->Father
      * Person的继承关系:Person[Grandson]<-Person[Son]<-Person[Father]
      */
    
    object test81{
      class Father
      class Son extends Father
      class Grandson extends Son
      class Person[-T] (val name: String) //-T逆变
      def main(args: Array[String]): Unit = {
        def makeMoney(person:Person[Son]) {
          println(s"你是${person.name},你应该去工作赚钱")
        }
        val father = new Person[Father]("father")
        val son = new Person[Son]("儿子")
        val grandson = new Person[Grandson]("孙子")
        makeMoney(father)
        makeMoney(son)
    //  makeMoney(grandson)  //  孙子还小,不需要赚钱
      }
    }
  • 相关阅读:
    hdu 1201 18岁生日
    线性代数
    关于pymongo的一些说明
    利用数组进行数据处理
    通用函数:快速的元素级数组函数
    IPython:一种交互式计算和开发环境
    关于一道面试题的思考
    wireshark中的抓包过滤器和显示过滤器
    wireshark推荐书籍
    wireshark 找不到网卡的解决办法
  • 原文地址:https://www.cnblogs.com/WeiKing/p/11683981.html
Copyright © 2011-2022 走看看