Kotlin汎型の詳細解と簡単な例

5835 ワード

Kotlin汎型詳細解
概要
一般クラスと関数は、具体的なタイプしか使えません。基本タイプか、カスタムクラスです。複数の種類のコードに適用できるように編纂するには、このような堅固な制約がコードに対して大きく制限されています。一方、OOPの多状態は一般化された機構を採用しており、SE 5種において、Javaは汎型を引用している。汎型、すなわち「パラメータ化タイプ」です。パラメータというと、最もよく知られているのは、方法を定義するときにイメージがあり、この方法を呼び出したときに実行を伝えます。パラメータ化のタイプはどう分かりますか?名前の通り、タイプを元の具体的なタイプからパラメータ化し、方法の変数パラメータに似ています。この場合、タイプもパラメータ形式と定義されて、使用/呼び出し時に具体的なタイプ(タイプの実装)が入ってきます。
Kotlinでは、依然として汎型、デカップリング類と関数と使用されるタイプとの間の制約が使用され、さらに使用方法はJavaと一致している。
汎型類
汎型クラスを宣言する

class Box<T>(t: T) {
  var value = t
}
通常、このようなクラスのインスタンスを作成するには、タイプパラメータを指定する必要があります。

val box: Box<Int> = Box<Int>(1)
しかし、タイプパラメータが推論によって得られる場合、例えば、コンストラクタパラメータタイプ、または他の手段によって推論される場合、タイプパラメータは省略される。

val box = Box(1) // 1      Int,                 Box&lt;Int>   
汎関数
汎関数は、そのクラスが汎型かどうかは関係ありません。汎関数によって、この関数はその所在クラスから独立して変化することができる。「Thinking in Java」には、いつでもできる限り汎型の方法を使うべきです。つまり汎型の方法を使えば、全体を汎型化する代わりに汎型の方法を使うべきです。このような一般的な考え方は、Kotlinの中でも継続できます。
次に、一般関数doPrintlnを宣言します。TがIntタイプの場合、そのビットの値を印刷します。TがStringタイプの場合は、すべて大文字で出力します。他のタイプの場合は、「T is not Int and String」を印刷します。

fun main(args: Array<String>) {
  val age = 23
  val name = "Jone"
  val person = true

  doPrintln(age) //   :3
  doPrintln(name) //   :JONE
  doPrintln(person) //   :T is not Int and String
}

fun <T> doPrintln(content: T) {

  when (content) {
    is Int -> println(content % 10) 
    is String -> println(content.toUpperCase())
    else -> println("T is not Int and String")
  }
}

注:
  • タイプのパラメータは、関数名の前に配置されます。
  • は、呼び出しにおいてタイプパラメータが明確に入力された場合、タイプパラメータは、関数名の後に置かれるべきである。パラメータタイプが入ってこない場合、コンパイラは着信値からパラメータタイプを自動的に推定します。
  • 拭き取る神秘の場所
    まずコードを見ます。
    
    class Box<T>(t : T) {
      var value = t
    }
    
    
    fun main(args: Array<String>) {
      var boxInt = Box<Int>(10)
      var boxString = Box<String>("Jone")
    
      println(boxInt.javaClass) //   :class com.teaphy.generic.Box
      println(boxString.javaClass) //   :class com.teaphy.generic.Box
    }
    
    
    一般的なタイプのBox<T>を宣言しましたが、行動の種類は違っています。しかし、私たちはその種類を獲得した時に、「class compone.teappy.generic.Box」を得ただけです。ここでは残酷な現実に直面しなければならない。汎型内部では、汎型パラメータの種類に関する情報は得られない。
    Javaであろうと、Kotlinであろうと、汎型は消去で実現されます。これは汎型を使うときに、タスクの具体的なタイプの情報が消去されます。唯一知っているのは、もう一つの対象を使うことです。例えば、Box<String>とBox<Int>は、実行時に思ったタイプで、いずれもBoxの例である。泛型を使う時、具体的なタイプの情報の消去は私達が直面することを知らないので、Kotlinの中でも私達のためにいくつかの参考になる解決策を提供しました。
  • タイプの協働
  • タイプの投射は
  • です。
  • 汎型制約
  • タイプ協働
    タイプ宣言の場合は、協働注釈修飾子(inまたはout)を使用します。この注釈はタイプパラメータの声明に現れており、したがって声明におけるタイプの変異と呼ばれている。汎型を使う場合、このタイプを使ってコンパイルしたらどんな効果がありますか?
    Tは協働注釈inによって修飾され、Rは協働注釈Outによって修飾されていると仮定する。
    
    internal interface Source<in T, out R> {
      fun mapT(t: T): Unit
      fun nextR(): R
    }
    
  • in T:Sourceのメンバー関数はTタイプしか消費できないことを確認し、Tタイプ
  • に戻ることができない。
  • out R:Sourceのメンバー関数はRタイプに戻りますが、Rタイプは消費できません。
  • 上記の説明から、協働注釈inとoutの意図を明確に知ることができます。実際には、タイプパラメータがこのクラスまたはインターフェースの用途を定義しています。消費に使うものですか?それとも戻すものですか?
    タイプ投射
    上に私達はすでに協働注釈inとoutの意図を了解しました。次に私達はinとoutを使って、有意義なことをします。下のコードを見てください。
    
    fun copy(from: Array<out String>, to: Array<Any>) {
      // ...
    }
    
    fun fill(dest: Array<in String>, value: String) {
      // ...
    }
    
    
    copy関数において、fromの汎型パラメータは協働注釈out修飾を使用しており、このパラメータはこの関数では消費できないこと、すなわちこの関数ではこのパラメータの操作が禁止されていることを意味している。
    fill関数については、destの汎型パラメータは協働注釈in修飾を使用し、Aray<in String>とJavaのAray<?super String>と同じで、つまり、CharSequence配列またはObject配列をfill関数のパラメータとして使用することができます。
    このような声明はKotlinではタイプ投射と呼ばれ、タイプ投射は主にパラメータに対する相対的な要因の制限を行い、このパラメータ類の安全操作を回避した。
    星印投射
    場合によっては、タイプパラメータのいかなる情報も知らないということを表したいかもしれませんが、それでも安全にそれを使用したいです。ここで「安全に使用する」というのは、パンチングタイプに対して1つのタイプの投射を定義します。このパンチングタイプのすべてのエンティティインスタンスが、この投射のサブタイプです。
    この問題に対して、Kotlinは、星号投射と呼ばれるシンタックスを提供する。
  • タイプがFooと定義されている場合、Tは協働タイプのパラメータであり、上界はTpper、Foo<>はFooに相当します。Tが未知の場合、Foo<>から安全にTpperタイプの値を読み取ることができます。
  • タイプがFooと定義されている場合、Tは逆協働タイプのパラメータであり、Foo<>はFooに相当する。Tが未知の場合、Foo<>に安全に任意のものを書き込むことができないと表している。
  • タイプがFooと定義されている場合、Tは協働タイプのパラメータであり、上界はTpperであり、読み取り値の場合、Foo<*>はFooに相当し、書き込み値の場合はFooに相当する。
  • 一つの汎型のタイプに複数のタイプのパラメータが存在する場合、各タイプのパラメータは単独で投射することができます。例えば、タイプがinterface Function<in T,out U>と定義されているなら、以下のいくつかの星番号投射があります。
  • Function<*,String>は、Function<in Nothing,String>を表す;
  • Function<Int,*>は、Function<Int,out Any?>を表す;
  • Function<>は、Function<in Nothing、out Any?>を表す。
  • 注意:星号投射はJavaの原生タイプと非常に似ていますが、安全に使えます。
    汎型制約
    与えられたタイプのパラメータに対して、許容されるタイプは、汎型制約によって制限され得る。
    上界
    最も一般的な制約は上界である:
    
    fun <T : Comparable<T>> sort(list: List<T>) {
      // ...
    }
    
    コロンの後に指定するタイプは、タイプパラメータの上界です。タイプパラメータTに対しては、Comprable<T>のサブタイプだけを使用することができます。たとえば、
    
    sort(listOf(1, 2, 3)) //   : Int   Comparable&lt;Int>     
    sort(listOf(HashMap<Int, String>())) //   : HashMap<Int, String>   
    Comparable<HashMap<Int, String>>     
    指定されていない場合は、デフォルトで使用される上界はAnyですか?タイプのパラメータを定義する括弧内では、唯一の上界のみを定義できます。同じタイプのパラメータが複数の上界を指定する必要がある場合は、別のwhere子文を使用する必要があります。
    
    fun <T> cloneWhenGreater(list: List<T>, threshold: T): List<T> where T : Comparable,
    T : Cloneable {
      return list.filter { it > threshold }.map { it.clone() }
    }
    
    
    読んでくれてありがとうございます。みなさんのご協力をお願いします。ありがとうございます。