zoukankan      html  css  js  c++  java
  • scala当中的类型参数

    类型参数主要就是研究scala当中的类或者scala当中的方法的泛型

    1、scala当中的类的泛型

            object Demo8 {

             def main(args: Array[String]): Unit = {

             val result1 = new MyClass("hello",50)

             val result2 = new MyClass[Any,Any]("zhangsan","Lisi");

             }

            }

              

            /**

             * 定义一个class类,接收两个参数,但是两个参数都是泛型,泛型的类型,会根据我们

             * 创建类的实例化对象的时候,动态的传递进行动态的推断

             * @param first

             * @param second

             * @tparam T

             * @tparam B

             */

            class MyClass[T,B](first:T,second:B){

             println(first+","+second)

       

    }

    2、函数的泛型

    我们的函数或者方法,也可以有类型参数

            object methodType{

             def getMiddle[T](canshu:T) ={

             canshu

             }

             def main(args: Array[String]): Unit = {

             // 从参数类型来推断类型

             println(getMiddle(Array("Bob", "had", "a", "little", "brother")).getClass.getTypeName)

             //指定类型,并保存为具体的函数。

             val f = getMiddle[String] _

             println(f("Bob"))

             }

    3、scala当中的上下界之泛型类型的限定

    在scala当中,我们可以通过上界或者下界来限定我们泛型的类型,类似于java当中的

    ? extends T ?号就表示我们使用的泛型,必须是T类型的子类,这种情况叫做上界

    ? super T ?号就表示我们使用的泛型,必须是T类型的父类,这种情况叫做下界

    在scala当中上界的表示方法使用的是 "<:", 这个符号就是表示上界,这种形式称之为泛型的上界

    在scala当中下界的表示方式使用的是 ">:", 这个符号就是表示下界,这种形式称之为泛型的下界

       

    3.1、泛型的上界限定

    我们可以通过上界的限定,限定我们传入的类型必须是某个类型的子类

       

            class Pair1[T <: Comparable[T]](val first: T, val second: T) {

             def smaller = if (first.compareTo(second) < 0) first else second

            }

              

            object Main1 extends App{

             override def main(args: Array[String]): Unit = {

             val p = new Pair1("hello", "Brooks")

             println(p.smaller)

             }

            }

       

     3.2、泛型的下界限定

    我们可以通过下界的限定,限定我们传入的类型必须是某个类型的父类

       

            class Pair2[T](val first: T, val second: T) {

             def replaceFirst[R >: T](newFirst: R) = new Pair2[R](newFirst, second)

             override def toString = "(" + first + "," + second + ")"

            }

              

            object Main2 extends App{

             override def main(args: Array[String]): Unit = {

             val p = new Pair2("Nick", "Alice")

             println(p)

             println(p.replaceFirst("Joke"))

             println(p)

             }

            }

       

    在Java中,T同时是A和B的子类型,称之为多界,形式如:<T extends A & B>。

    在Scala中,对上界和下界不能有多个,但是可以使用混合类型,如:[T <: A with B]。

    在Java中,不支持下界的多界形式。如:<T super A & B>这是不支持的。

    在Scala中,对复合类型依然可以使用下界,如:[T >: A with B]。

       

       

    4、scala当中的视图界定

    说白了就是将我们的泛型转化成了具体的类型

    在Scala中,如果你想标记某一个泛型可以隐式的转换为另一个泛型,可以使用:[T <% Comparable[T]],由于Scala的Int类型没有实现Comparable接口,所以我们需要将Int类型隐式的转换为RichInt类型,比如:

    我们如果需要比较两个值的大小,那么我们的两个值必须是Comparable的子类,那么我们可以使用泛型 T <% Comparable 来限制我们泛型必须是Comparable的子类,并且我们的泛型在执行真正比较的方法的时候,会根据我们传入的类型,自动推断,进行隐式的转换,例如我们传入4,2 进行比较,那么我们会将4, 2 这两个类型做自动推断,转换成真正的RichInt类型然后再继续进行比较

       

    /**

    * 使用 <% 来实现我们类型的隐式转换

    * @param first

    * @param second

    * @tparam T

    */

    class Pair3[T <% Comparable[T]](val first: T, val second: T) {

    def smaller = if (first.compareTo(second) < 0) first else second

    override def toString = "(" + first + "," + second + ")"

    }

       

    object Main3 extends App {

    val p = new Pair3(4, 2)

    println(p.smaller)

    }

       

    5、scala当中的协变,逆变和非变

    协变和逆变主要是用来解决参数化类型的泛化问题。Scala的协变与逆变是非常有特色的,完全解决了Java中泛型的一大缺憾;举例来说,Java中,如果有 A是 B的子类,但 Card[A] 却不是 Card[B] 的子类;而 Scala 中,只要灵活使用协变与逆变,就可以解决此类 Java 泛型问题;

    由于参数化类型的参数(参数类型)是可变的,当两个参数化类型的参数是继承关系(可泛化),那被参数化的类型是否也可以泛化呢?Java中这种情况下是不可泛化的,然而Scala提供了三个选择,即协变("+")、逆变("-")和非变。

    下面说一下三种情况的含义,首先假设有参数化特征Queue,那它可以有如下三种定义。

    1. trait Queue[T] {}

      这是非变情况。这种情况下,当类型B是类型A的子类型,则Queue[B]与Queue[A]没有任何从属关系,这种情况是和Java一样的。

    2. trait Queue[+T] {} 
      这是协变情况。这种情况下,当类型B是类型A的子类型,则Queue[B]也可以认为是Queue[A]的子类型,即Queue[B]可以泛化为Queue[A]。也就是被参数化类型的泛化方向与参数类型的方向是一致的,所以称为协变。
    3.   trait Queue[-T] {} 

      这是逆变情况。这种情况下,当类型B是类型A的子类型,则Queue[A]反过来可以认为是Queue[B]的子类型。也就是被参数化类型的泛化方向与参数类型的方向是相反的,所以称为逆变。 

    协变、逆变、非变总结

    • C[+T]:如果A是B的子类,那么C[A]是C[B]的子类。
    • C[-T]:如果A是B的子类,那么C[B]是C[A]的子类。
    • C[T]: 无论A和B是什么关系,C[A]和C[B]没有从属关系。

       

    案例

    package com.starzy.scala

       

    class Super

    class Sub extends Super

    //协变

    class Temp1[+A](title: String)

    //逆变

    class Temp2[-A](title: String)

    //非变

    class Temp3[A](title: String)

       

    object Covariance_demo{

    def main(args: Array[String]) {

    //支持协变 Temp1[Sub]还是Temp1[Super]的子类

    val t1: Temp1[Super] = new Temp1[Sub]("hello scala!!!")

    //支持逆变 Temp1[Super]Temp1[Sub]的子类

    val t2: Temp2[Sub] = new Temp2[Super]("hello scala!!!")

    //支持非变 Temp3[Super]Temp3[Sub]没有从属关系,如下代码会报错

    //val t3: Temp3[Sub] = new Temp3[Super]("hello scala!!!")

    //val t4: Temp3[Super] = new Temp3[Sub]("hello scala!!!")

    println(t1.toString)

    println(t2.toString)

    }

    }

       

  • 相关阅读:
    解决前端跨域请求的几种方式
    使用excel 展现数据库内容
    win7 安装windows 服务 报错 System.Security.SecurityException 解决方法 An exception occurred during the Install phase. System.Security.SecurityException: The so
    java 查看线程死锁
    linux 配置 java 环境变量
    数据库性能优化
    C#中静态与非静态方法比较
    apache日志切割工具cronolog安装配置
    虚拟机克隆后网卡有问题解决方法
    vs2015工具箱突然没有了
  • 原文地址:https://www.cnblogs.com/starzy/p/10466597.html
Copyright © 2011-2022 走看看