2017-10-22 11 views
6

Tといくつかのメタデータの配列(またはリスト)が含まれています。私はインターフェイスの最も簡単な実装を記述する場合Kotlinのジェネリックアレイ<T>は、「Reified typeパラメータとしてTを使用できません。代わりにクラスを使用しますが、リスト<T>はありません。

interface DataWithMetadata<T> { 
    val someMetadata: Int 
    fun getData(): Array<T> 
} 

は、私が上でコンパイルエラーを取得emptyArray():「具体化型パラメータとしてTを使用することはできません代わりにクラスを使用します。。」

class ArrayWithMetadata<T>(override val someMetadata: Int): DataWithMetadata<T> { 
    private var myData: Array<T> = emptyArray() 

    override fun getData(): Array<T> { 
     return myData 
    } 

    fun addData(moreData: Array<T>) { 
     this.myData += moreData 
    } 
} 

私はインターフェイスとリストへの実装の両方を変更する場合は、私はコンパイル時の問題を持っていない:

interface DataWithMetadata<T> { 
    val someMetadata: Int 
    fun getData(): List<T> 
} 

class ListWithMetadata<T>(override val someMetadata: Int): DataWithMetadata<T> { 
    private var myData: List<T> = emptyList() 

    override fun getData(): List<T> { 
     return myData 
    } 

    fun addData(moreData: Array<T>) { 
     this.myData += moreData 
    } 
} 

私は私の問題で内部Kotlinのジェネリクスでいくつかの興味深い教訓があると疑われます。コンパイラが何をしているのか、Arrayはなぜ失敗するのか誰にでも教えてもらえますか?このコンテキストでArrayの実装をコンパイルするための慣用的な方法はありますか?

ボーナス質問:私がArray over Listに到達した唯一の理由は、コトリン開発者がアレイを好むことがよくあることです。これが事実ですか、そうなら、なぜですか?

答えて

5

kotlin STDLIB(JVM)でemptyArray()の宣言を見ると、私たちはreified型パラメータに気づく:

public inline fun <reified @PureReifiable T> emptyArray(): Array<T> 

reified型パラメータを使用すると、コンパイル時にTのクラスへのアクセス権を持っていることを意味しT::classのようにアクセスできます。 Kotlin referencereifiedタイプのパラメータの詳細については、こちらをご覧ください。 Array<T>はJava T[]にコンパイルするので、コンパイル時にタイプを知る必要があります。したがって、reifiedパラメータです。

:さんは emptyList()の実装を見てみましょう、今

fun <T> emptyArray() : Array<T> = Array(0, { throw Exception() }) 

Cannot use T as a reified type parameter. Use a class instead.


:あなたはreifiedキーワードを指定せずにemptyArray()関数を記述しようとすると、コンパイルエラーを取得します

public fun <T> emptyList(): List<T> = EmptyList 

この実装では、パラメータTはまったく必要ありません。内部オブジェクトEmptyListを返します。それ自体はList<Nothing>から継承されます。 kotlinタイプNothingは、throwキーワードの返品タイプであり、(reference)という値のないの値です。メソッドがNothingを返す場合、isはその場所で例外をスローするのと同じです。したがって、EmptyList.get()を呼び出すたびに例外が返されることをコンパイラーが知っているので、安全にNothingをここで使用することができます。


ボーナス質問:

は、JavaやC++から来て、私はその配列を使用してはるかに簡単であることをArrayListまたはstd::vectorするために使用しています。私は数ヶ月間kotlinを使用しています。ソースコードを書くときには、配列とリストの間に大きな違いはありません。両方とも、同様の方法で動作する有用な拡張関数がたくさんあります。しかし、Kotlinコンパイラは配列とリストを非常に異なったものに扱います.Jot相互運用性はKotlinチームにとって非常に重要です。私は通常、リストを使用する方が好きです。あなたのケースでもそれをお勧めします。

2

問題はArrayの一般的な要素の型が宣言に見られるように、ここでreified typeパラメータによって示されコンパイル時、で知られなければならないこと、である:

public inline fun <reified @PureReifiable T> emptyArray(): Array<T> 

それだけですArray<String>またはArray<Int>のような具体的な配列を作成できますが、タイプはArray<T>ではありません。

このanswerには、いくつかの回避策があります。あなたが適切な方法を見つけることを願っています。

関連する問題