Scalaジェネリック、上限、下限、ビューの使用法

ジェネリック

使用例

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

タイプ制約の上限と下限

上界

Javaのジェネリックスは、extendsキーワードを使用して、特定のタイプがAのサブタイプであることを示しています。この形式が上限になり、構文は次のようになります。

<T extends A><? extends A>

Scalaのジェネリックスは、特定のタイプがAのサブタイプであることを示しており、<:を使用するための構文は次のとおりです。

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

上限の適用は、
IntとFloatなどを直接比較するための一般的なクラスで記述できます。Comparableインターフェイスの値が実装されています。コードは次のとおりです。

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
  }

下限

JavaジェネリックスでタイプAの親タイプとして特定のクラスを識別するには、次のようにsuperキーワードを使用します。

<T super A><? super A>

Scalaでは、下限または下限は次のように>:キーワードを使用します。

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

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


下限の使用概要任意の型を下限に渡すことができます。渡されたものがTのサブクラスの場合、T型に従って処理され、Tに関係のないクラスはオブジェクトとして処理されます。 。
つまり、下限はパラメータを自由に渡すことができますが、処理方法は異なります。

定義を表示

つまり、ビュー定義は自動的に暗黙的な変換を使用してターゲットタイプに変換し、純粋に下限のメソッドは自動的に暗黙的な変換を使用しませんが、ビュー定義は
文法になります:[T <%A]または<? <%A>:定義されているかどうかを示します入力パラメータタイプとAタイプの間の暗黙的な変換の場合、暗黙的な変換が自動的に呼び出され、入力パラメータがAタイプに
変換されます例:暗黙的な変換を自分で記述します。そして、Personオブジェクトの年齢をビュー定義と比較します。

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

コンテキスト化

ビュー境界と同様に、コンテキスト境界(コンテキスト境界)も暗黙的なパラメーターの構文糖衣です。「コンテキスト境界」の概念は、文法上の便宜のために導入されています。

例:コンテキストバウンド+暗黙のパラメーターを使用して、2人の年齢を比較します

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

共変性、反変性、不変性

リスト[T]などのベルトタイプのジェネリックパラメーターの場合、AとサブタイプBがリスト[B]を満たしている場合はリスト[A]サブタイプであり
、ベルトの共変(共変)と呼ばれますリストなどのジェネリックパラメーターのタイプ[T]、AとそのサブタイプBについて、List [A]がList [B]のサブタイプであることが満たされる場合、それは反変と呼ばれます。
それが共変でも反変でもない場合、それは不変です。たとえば、List [T]の場合、AとそのサブタイプBの場合、List [A]とList [B]の間に親子関係はありません
。Javaのすべてのジェネリック型は不変です。つまり、ListとListは不変ではありません。親子関係があります。
Scalaでは、型を定義するときに、文法的な定義を通じて共変または反変として宣言できます。宣言を行わない場合、デフォルトは変更されません。
例:
List [+ T]は、次の場合に共変として定義されます。typeが宣言されているため、List [String]はListです。[Any]
List [-T]のサブクラスは、型宣言で反変として定義されているため、List [Any]は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){
    
    }

おすすめ

転載: blog.csdn.net/zhangxm_qz/article/details/108107917