Kotlin泛型Array <T>导致“不能使用T作为一个实体类型参数。 用类来代替“但是List <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泛型。 任何人都可以告诉我什么编译器正在做的引擎盖下,为什么数组失败,但列表不? 有没有一种惯用的方法来使数组实现在这种情况下编译?

奖金问题:我在列表上列出的唯一原因是我经常看到Kotlin开发者喜欢数组。 是这样,如果是这样,为什么?

看看kotlin stdlib(jvm)中emptyArray()的声明,我们注意到了reified类型参数:

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

reified类型参数意味着你可以在编译时访问T的类,并且可以像T::class一样访问它。 您可以在Kotlin参考中阅读更多关于reified类型参数的信息 。 由于Array<T>编译为java T[] ,因此我们需要在编译时知道类型,因此是reified参数。 如果你尝试写一个没有reified关键字的emptyArray()函数,你会得到一个编译错误:

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

不能使用T作为实体类型参数。 改用班级。


现在让我们来看看emptyList()的实现:

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

这个实现根本不需要参数T 它只是返回内部对象EmptyList ,它本身从List<Nothing>继承。 kotlin类型Nothingthrow关键字的返回类型,是一个从不存在的值 ( 引用 )。 如果一个方法返回Nothing ,就等于在那个地方抛出一个异常。 所以我们可以在这里安全的使用Nothing ,因为每次我们调用EmptyList.get() ,编译器就知道这会返回一个异常。


奖金问题:

来自Java和C ++,我习惯于使用ArrayListstd::vector来更容易地使用这个数组。 我现在使用kotlin几个月,在编写源代码时,我通常不会在数组和列表之间看到很大的区别。 两者都有很多有用的扩展函数,其行为方式类似。 然而,Kotlin编译器处理数组和列表的方式非常不同,因为Java的互操作性对于Kotlin团队来说非常重要。 我通常更喜欢使用列表,这也是我建议你的情况。

问题是,在编译时必须知道Array的通用元素类型,在声明中可以看到这是由通用类型参数表示的:

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

只能创建像Array<String>Array<Int>而不是Array<T>类型的具体Array<T>

在这个答案中 ,你可以找到几个解决方法。 希望你找到一个合适的方法。