Scala generics, upper bound, lower bound, view usage

Generic

Usage example

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

Type constraint upper and lower bounds

Upper Bound

Generics in java indicate that a certain type is a subtype of A, using the extends keyword, this form becomes the upper bound, the syntax is as follows:

<T extends A><? extends A>

Generics in scala indicate that a certain type is a subtype of A. The syntax for using <: is as follows:

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

The application of the upper bound The code
for direct comparison of the value of the Comparable interface that implements the Comparable interface can be carried out by writing general classes between Int and Float. The
code is as follows

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
  }

Lower bound

To identify a certain class as the parent type of Type A in Java generics, use the super keyword, as follows:

<T super A><? super A>

In Scala, the lower bound or lower bound uses the >: keyword as follows:

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

Example

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")
    }
  }

Summary
of the use of the lower bound Any type can be passed in for the lower bound. If the passed in is a subclass of T, it will be processed according to the T type, and the classes irrelevant to T will be processed as object.
In other words, the lower bound can pass parameters at will, but the processing method is different.

View definition

That is to say, the view definition will automatically use implicit conversion to convert to the target type, and the purely lower bound method will not automatically use implicit conversion, but the view definition can be
grammar: [T<%A] or <?<%A>: indicates if it is defined If the implicit conversion between the input parameter type and the A type is used, then the implicit conversion will be automatically called to convert the input parameter to the A type.
Example: Write the implicit conversion by yourself and compare the age of the Person object with the view definition.

//创建隐式转换,自动将 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
//  }

Contextualization

Like view bounds, context bounds (context bounds) are also syntactic sugar for implicit parameters. The concept of "context bounds" is introduced for grammatical convenience.

Example: Use context bound + implicit parameters to compare the age of two Persons

//定义隐式值
  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)
}

Covariance, contravariance and invariance

For a belt type generic parameters, such as List [T], if A and subtype B, satisfies List [B] is List [A] subtype, then called covariant (covariant)
for a belt The type of generic parameter, such as List[T], if for A and its subtype B, it is satisfied that List[A] is a subtype of List[B], then it is called contravariant.
If it is neither covariant nor contravariant, then it is invariant. For example, List[T], if for A and its subtype B, there is no parent-child relationship between List[A] and List[B]
. All generic types in java are invariant, that is, List and List do not have any parent-child relationship.
In Scala, when you define a type, you can declare it as covariant or contravariant through a grammatical definition. If you don’t make a declaration, the default is unchanged. For
example:
List[+T] is defined as covariant when the type is declared, so List[String] is List The subclass of [Any]
List[-T] is defined as contravariant in the type declaration, so List[Any] is an example of a subclass of 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){
    
    }

Guess you like

Origin blog.csdn.net/zhangxm_qz/article/details/108107917