Scala genéricos, límite superior, límite inferior, uso de la vista

Genérico

Ejemplo de uso

def test={
    
    
  //应用1
  val msg = new IntMessage(1)
  println(msg)
  val msg2 = new StringMessage[String]("class")
  println(msg2)
  //应用2
  val class01 = new EnglishClass[String,String,String]("春季","大数据","初级")
  val class02 = new EnglishClass[String,String,Int]("春季","大数据",1)
  //应用3
  val list1 = List("hello","tom");
  println(midList[String](list1))
  val list2 = List(1,2);
  println(midList[Int](list2))
}

  //应用案例1
abstract  class Message[T](s:T){
    
    
  def get():T ={
    
    
    s
  }
}
class IntMessage[Int](s:Int) extends  Message{
    
    
}
class StringMessage[String](s:String) extends  Message{
    
    
}
  //应用案例2
  class EnglishClass[A,B,C](val season:A,val name:B,val cType:C){
    
    }

//应用案例3
  def midList[E](l:List[E]):E={
    
    
    l(l.length/2)
  }

Límites superior e inferior de la restricción de tipo

Límite superior

Los genéricos en Java indican que un cierto tipo es un subtipo de A, usando la palabra clave extiende, esta forma se convierte en el límite superior, la sintaxis es la siguiente:

<T extends A><? extends A>

Los genéricos en scala indican que cierto tipo es un subtipo de A, y la sintaxis para usar <: es la siguiente:

[T<:A][_<:A]

La aplicación del límite superior
se puede escribir en clases generales para la comparación directa entre Int y Float, etc. Se implementa el valor de la interfaz Comparable. El
código es el siguiente

def test={
    
    
    //传统方式
    val comparaInt = new ComparaInt(10,20)
    println(comparaInt.greater)

    //上限 方式
    //这种方式直接报错,因为 scala 的 Int 类型没有实现 Comparable
    //  val commonCompare1 = new CommonCompare(10,20)
    //  println(commonCompare1.greater)
    //传入 Integer 得到正常结果 20
    val commonCompare2 = new CommonCompare(Integer.valueOf(10),Integer.valueOf(20))
    println(commonCompare2.greater)
    //传入 Int 得到正常结果 20
    //这是因为 predef 中定义了隐式转换,这里声明了 需要 java.lang.Integer 传入了 Int 编译器自动转换
    val commonCompare3 = new CommonCompare[java.lang.Integer](10,20)
    println(commonCompare3.greater)

//使用 视图的时候 可以自动进行 隐式转换 而不必 声明需要 java.lang.Integer
    val commonCompare4 = new CommonCompare2(10,20)
    println(commonCompare4.greater)

  }
  //传统方法
  class ComparaInt(n1:Int,n2:Int){
    
    
    def greater  = if(n1>n2) n1 else n2
  }
  //泛型方法
  class CommonCompare[T <:Comparable[T]](obj1:T,obj2:T){
    
    
    def greater = if(obj1.compareTo(obj2)>0)obj1 else obj2
  }

  //泛型方法 视图 方式
  class CommonCompare2[T <%Comparable[T]](obj1:T,obj2:T){
    
    
    def greater = if(obj1.compareTo(obj2)>0)obj1 else obj2
  }

Límite inferior

Para identificar una determinada clase como el tipo principal de Tipo A en los genéricos de Java, utilice la palabra clave super, de la siguiente manera:

<T super A><? super A>

En Scala, el límite inferior o el límite inferior utiliza la palabra clave>: de la siguiente manera:

 [T >:A][_>:A]

Ejemplo

def test={
    
    
  //满足下界的约束  Hello Earth
 sound(Seq(new Earth ,new Earth)).map(_.sound())
  //满足下界的约束 Hello Animal
 sound(Seq(new Animal,new Animal)).map(_.sound())
  //满足下界的约束  Hello Bird   这里虽然不是 Animal的父类也可以满足下界的约束  实际上是将 Bird 转换成了Animal类型
  sound(Seq(new Bird,new Bird)).map(_.sound())

  //如下代码编译执行都没有问题  因此不能用上界的思路去推导,是否满足
  sound(Seq(new Moon,new Moon))
}
  def sound[T>:Animal](things:Seq[T])=things

class Earth{
    
    
  def sound(){
    
    
    println("Hello Earth")
  }
}
  class Animal extends  Earth {
    
    
    override def sound(){
    
    
      println("Hello Animal")
    }
  }
  class Bird extends  Animal {
    
    
    override def sound(){
    
    
      println("Hello Bird")
    }
  }
  class Moon{
    
    
    def sound(){
    
    
      println("Hello Moon")
    }
  }

Resumen
del uso del límite inferior Se puede pasar cualquier tipo para el límite inferior. Si el paso es una subclase de T, se procesará de acuerdo con el tipo T, y las clases irrelevantes para T se procesarán como objeto .
En otras palabras, el límite inferior puede pasar parámetros a voluntad, pero el método de procesamiento es diferente.

Ver definición

Es decir, la definición de vista usará automáticamente la conversión implícita para convertir al tipo de destino, y el método de límite inferior puro no usará automáticamente la conversión implícita, pero la definición de vista puede ser
gramatical: [T <% A] o <? <% A>: indica si está definido Si la conversión implícita entre el tipo de parámetro de entrada y el tipo A, entonces la conversión implícita se llamará automáticamente para convertir el parámetro de entrada al tipo A.
Ejemplo: Escriba la conversión implícita usted mismo y compare la edad del objeto Person con la definición de vista.

//创建隐式转换,自动将 person 对象转换为Ordered的对象
  implicit  def personToOrderedPerson(p:Person3) = new Ordered[Person3]{
    
    
    override def compare(that: Person3): Int = {
    
    
      p.age-that.age
    }
  }

  def test={
    
    
    val p1 = new Person3("jim",10)
    val p2 = new Person3("tom",12);

    import impli.MyImplicit._
    //创建时自动
    val compareComm3 = new CompareComm(p1,p2)
    println(compareComm3.getter2)

  }
  class Person3(val name:String,val age:Int){
    
    
    override def toString: String = this.name+"  "+this.age
  }


  class CompareComm[T<% Ordered[T]](obj1:T,obj2:T){
    
       //这种写法可以使用隐式转换
    def getter2 =  if(obj1.compareTo(obj2)>0) obj1 else obj2
  }

//  class CompareComm2[T<: Ordered[T]](obj1:T,obj2:T){   //这种写法不能使用隐式转换
//    def getter2 =  if(obj1.compareTo(obj2)>0) obj1 else obj2
//  }

Contextualización

Al igual que los límites de vista, los límites de contexto (límites de contexto) también son azúcar sintáctico para los parámetros implícitos. El concepto de "límites de contexto" se introduce por conveniencia gramatical.

Ejemplo: utilice parámetros implícitos + enlazados al contexto para comparar la edad de dos personas

//定义隐式值
  implicit  val personComp=  new Ordering[Person4]{
    
    
    override def compare(x: Person4, y: Person4): Int = {
    
    
      x.age-y.age
    }
  }
  class Person4(val name:String,val age:Int){
    
    
    override def toString: String = this.name+"  "+this.age
  }
  //类构造函数的参数可以放在 两个括号中
  //class TT (val name:String)(val age:Int){}
  //方式一 构造参数中使用隐式转换
  //构造函数的参数可以放在两个括号中
  // class CompareComm[T:Ordering](obj1:T,obj2:T)(implicit comparator:Ordering[T]){
    
    
  class CompareComm[T:Ordering](obj1:T,obj2:T)(implicit comparator:Ordering[T]){
    
    
    def greater = if(comparator.compare(obj1,obj2)>0)obj1 else obj2;
  }
  //方式二 将隐式转换放在方法内
  class CompareComm2[T:Ordering](obj1:T,obj2:T){
    
    
    def greater ={
    
    
       def f1 (implicit comparator:Ordering[T]) ={
    
    
         comparator.compare(obj1,obj2)
       }
      if(f1> 0) obj1 else obj2
    }
  }
  //方式三 使用 implicitly 最简单
  class CompareComm3[T:Ordering](obj1:T,obj2:T){
    
    
    def greater ={
    
    
      //这句话本身就是隐式转换,获取到personComp
      implicit val comparator =implicitly[Ordering[T]]
      if(comparator.compare(obj1,obj2)> 0) obj1 else obj2
    }
  }

def test={
    
    
  val p1 = new Person4("jim",10)
  val p2 = new Person4("tom",12);
  //方式一
  val comp = new CompareComm[Person4](p1,p2)
  println(comp.greater)

  //方式二
  val comp2 = new CompareComm2[Person4](p1,p2)
  println(comp2.greater)

  //方式三
  val comp3 = new CompareComm3[Person4](p1,p2)
  println(comp3.greater)
}

Covarianza, contravarianza e invariancia

Para un tipo de cinturón, los parámetros genéricos, como Lista [T], si A y el subtipo B, satisface el subtipo Lista [B] es Lista [A], luego se llama covariante (covariante)
para un cinturón El tipo de parámetro genérico, como Lista [T], si para A y su subtipo B, se satisface que Lista [A] es un subtipo de Lista [B], entonces se llama contravariante.
Si no es ni covariante ni contravariante, entonces es invariante. Por ejemplo, List [T], si para A y su subtipo B, no hay una relación padre-hijo entre List [A] y List [B]
. Todos los tipos genéricos en Java son invariantes, es decir, List y List no tener alguna relación entre padres e hijos.
En Scala, cuando define un tipo, puede declararlo como covariante o contravariante a través de una definición gramatical. Si no hace una declaración, el valor predeterminado no cambia. Por
ejemplo:
List [+ T] se define como covariante cuando el type se declara, por lo que List [String] es List La subclase de [Any]
List [-T] se define como contravariante en la declaración de tipo, por lo que List [Any] es un ejemplo de una subclase de List [String]

def test={
    
    
     //协变
     //由于 协变 Tclass[Super] 是Tclass[Sub] 的父类 所以 可以直接赋值不报错
    val t2:Tclass[Super] = new Tclass[Sub](new Sub())
    //同理该行报错 父类型变量不能赋值给子类型
    // val t3:Tclass[Sub] = new Tclass[Super](new Super())

    //逆变
    //由于 协变 Tclass[Super] 是Tclass[Sub] 的子类类 父类不能赋值给子类 所以该行报错
   // val t4:Tclass2[Super] = new Tclass2[Sub](new Sub())
    //同理该行不报错
     val t5:Tclass2[Sub] = new Tclass2[Super](new Super())
    //不变
    //由于 不变 Tclass[Super] 是Tclass[Sub] 没有父子关系 因此  类型不匹配不能相互赋值  所以两行都报错
    // val t6:Tclass2[Super] = new Tclass2[Sub](new Sub())
    //val t7:Tclass3[Sub] = new Tclass3[Super](new Super())
  }
  //定义两个有父子关系的类  Super 和 Sub
  class Super
  class Sub extends  Super
  //定义协变类
  class Tclass[+T](param:T){
    
    }
  //定义逆变类
  class Tclass2[-T](param:T){
    
    }
  //定义不变类
  class Tclass3[T](param:T){
    
    }

Supongo que te gusta

Origin blog.csdn.net/zhangxm_qz/article/details/108107917
Recomendado
Clasificación