2017-07-18 5 views
2

Kotlinのreified型パラメータは、型パラメータの消去を防ぎ、実行時に型パラメータを知ることを可能にします。Kotlin Reified型パラメータは、関数本体に型パラメータとして使用できません。

inline fun <reified T> isA(value: Any) = value is T 

をしかし、私はそれが消去タイプであるというメッセージを取得する代わりに、スタンドアロンの型パラメータとして「T」を使用しようとすると、これは次のコードをコンパイルし、期待通りに実行することができます。これは例示を目的とするものであり、次のコードによって実証さだけ

inline fun <reified T> isListOfA(name: String): Boolean { 
    val candidate = Class.forName(name) 
    return candidate is List<T> 
} 

が、これは技術的な制限によるものですか?もしそうなら、その限界は何ですか?

+0

これは身元確認の問題ではありません。あなたは 'canditate is List 'をすることさえできません。 –

答えて

0

を私が望む形の答えを得るために適切に私の質問。ここでの答えのほとんどは、「あなたがJavaでそれを行うことができないため」のバリエーションです。さて、あなたはJavaでx instanceof Tを実行することはできませんが、あなたはx is TをKotlinで行うことができます。私は、Javaのルールではなく、根本的な実際のロードブロッキングを探しています。結局、ルールは壊れてしまいます。

ここで最初の答えに私のコメントからは、再公式化質問は:objectref is SomeClass<T>は同じメカニズムで動作させることができない理由objectref is Tは、いくつかのメカニズムXでKotlinで動作するようにすることができれば?

tl; dr答え:実行時にSomeClass<T>Classオブジェクトが存在しないためです。

長い答え:最初にis Tinstanceofバイトコード命令を生成するメカニズムXを理解する必要があります。この命令は、objectrefと、いくつかのクラスCの名前Nを取ります。ここで、Nは、コンパイラのコンテキストから決定されます。実行時にNに由来するクラスCを使用してobjectref is Tの表現を評価します。この評価を行うには、Cのクラスオブジェクトをインスタンス化する必要があります。従って、objectref is SomeClass<T>に対してこの同じメカニズムを使用する場合、NSomeClass<T>になります。型消去のために、SomeClass<T>のクラスオブジェクトは存在しないので、必要なinstanceof命令を生成することはできず、同じメカニズムを適用することができません。また、instanceof命令は、SomeClass<T>という形式の名前をとることはできません。したがって、objectref is SomeClass<T>を動作させる場合は、他のメカニズムYを見つけてKotlinに実装する必要があります。そのようなメカニズムは存在しても存在しなくてもよい。

これは、これが他の回答のいくつかと同じことを言う人もいることはわかっています。しかし、私の学習スタイルは、金属がどのように機能するかを理解し、それを抽象モデルと合成することが、より良くても悪いことでもあります。この場合、消去のJavaジェネリックスの概念は抽象モデル(またはその一部)です。本当に、「消去」は、私がそれが実際の実装で実現されていることの少なくとも一つの方法を理解していない限り、私にはすこし気分になります。

1

コンパイル時にジェネリック型パラメータTObject/upper-bounded型に消去するので、Kotlinではこれを行う方法がありません。

最初のアプローチは、value is Tは、例えば、具体化タイプで呼び出しサイトの機能の中にインライン化されるので、それは作業することができます

//val is_string = isA<String>(1) // inline into the call-site function as below: 


val i:Int = 1 
//     v--- the actual type argument is inlined here 
val is_string = 1 is String 
+0

はい、実際の型引数が "is T"の "is String"としてインライン化されることになります。それが可能な場合、なぜそれが "List "のためにインライン化することができないのですか? "リスト"?それは私が求めている質問です。 – roobyroo

+0

@roobyrooいいえ、あなたは**タイプ消去のために**コンパイル時に発生するので、javaは** reified **ジェネリックタイプをサポートしていません。 –

2

ことをやってからあなたを防ぐ技術的な制限がgenerics type erasure on JVMです。基本的に、実行時にジェネリックタイプList<T>のオブジェクトは、オブジェクトで動作するちょうどListになります。コンパイル時には、型の安全性が代入と関数呼び出しのためにチェックされます。実際の型パラメータTは、コンパイル時にのみ存在し、その後消去されます。実行時に復元することはできません(少なくとも現在は、Project Valhallaがあるため、JVMのランタイム統合ジェネリックを1日導入する可能性があります)。

非インラインのKotlin関数(および非修飾型パラメータ)では、通常の型パラメータも消去されるため、チェックの最初の種類はvalue is Tですらできませんでした。具体化型パラメータを持つ

、関数本体は、実際の(または推測された)と、その呼び出しサイトでインライン化されますTの代わりにパラメータを入力します。あなたはisA<String>("abc")を呼び出すときに、呼び出しサイトはStringためinstanceofチェックしてバイトコードを持っています。

ではなく、something is List<String>であることを確認することができます。タイプ引数は実行時にはどこにも格納されません。

また、isA<List<String>>(listOf(1, 2, 3))trueを返すことに注意してください。 Kotlinではこの奇妙なケースがどのように処理されるのですか。タイプの非ジェネリック部分だけが実際に実行時にチェックされることができます。

0

パラメータ化された型は、実行時に常に消去されます。したがって、Tインスタンスで、TおよびVが有効であるかハードコードされているかにかかわらず、T<V>インスタンスではないことを確認できます。それはチェックしているため、その名前を持つタイプではなく、チェックの、インスタンスリストのであれば、その名前の型が期待されるリストのタイプがある場合

しかし、それが可能であったとしても、あなたのコード例では意味がありません。 。

あなたがオブジェクトのインスタンスを持っており、それだけで期待されるタイプのアイテムを含むリストだということを確認したい場合は、あなたはまだこのような何か書くことができます:私は策定していない明らかに

inline fun <reified T> isListOfA(instance: Any) 
    = instance is List<*> && instance.all { it is T } 
+1

注:この 'isListOfA'チェックは、ある時点で' String'だけを含み 'isListOfA (list)'のチェックを渡した 'MutableList 'の読み取り専用ビューを考慮しますが、後で 'Int 'が追加されましたが、すでにリストをすべての項目が' String'であると期待しているコードに渡していたため、 'ClassCastException'で失敗しました。 – hotkey

関連する問題