问题描述
我有一个接口,其中包含T的数组(或列表)和一些元数据.
I have an interface that contains an array (or list) of T and some metadata.
interface DataWithMetadata<T> {
val someMetadata: Int
fun getData(): Array<T>
}
如果我编写接口的最简单的实现,则会在emptyArray()
上收到编译错误:不能将T用作化类型参数.请改用类."
If I write the simplest implementation of the interface, I get a compile error on the emptyArray()
: "Cannot use T as a reified type parameter. Use a class instead."
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
}
}
但是,如果我同时将接口和实现都更改为列表,则不会有编译时问题:
However, if I change both the interface and the implementation to a list, I have no compile-time issues:
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失败但List不会失败?有没有一种惯用的方法可以使Array实现在这种情况下进行编译?
I suspect there is some interesting lesson in Kotlin generics inside my issue. Can anyone tell me what the compiler is doing under the hood and why Array fails but List does not? Is there an idiomatic way to make the Array implementation compile in this context?
奖金问题:我获得Array over List的唯一原因是,我经常看到Kotlin开发人员偏爱Arrays.是这样吗?如果是这样,为什么?
Bonus question: The only reason I reached for Array over List is that I often see Kotlin developers favor Arrays. Is this the case, and if so, why?
推荐答案
看看kotlin stdlib(jvm)中emptyArray()
的声明,我们注意到reified
类型参数:
Looking at the declaration of emptyArray()
in the kotlin stdlib (jvm), we notice the reified
type parameter:
public inline fun <reified @PureReifiable T> emptyArray(): Array<T>
reified
类型参数意味着您可以在编译时访问T
的类,并且可以像T::class
一样访问它.您可以在科林参考.由于Array<T>
可以编译为Java T[]
,因此我们需要在编译时知道类型,因此需要reified
参数.如果您尝试编写不带reified
关键字的emptyArray()函数,则会出现编译器错误:
The reified
type parameter means that you have access to the class of T
at compile-time and can access it like T::class
. You can read more about reified
type parameters in the Kotlin reference. Since Array<T>
compiles to java T[]
, we need to know the type at compile-time, hence the reified
parameter. If you try writing an emptyArray() function without the reified
keyword, you'll get a compiler error:
fun <T> emptyArray() : Array<T> = Array(0, { throw Exception() })
现在,让我们看一下emptyList()
的实现:
Now, let's take a look at the implementation of emptyList()
:
public fun <T> emptyList(): List<T> = EmptyList
此实现完全不需要参数T
.它仅返回内部对象EmptyList
,该对象本身是从List<Nothing>
继承的. Kotlin类型Nothing
是throw
关键字的返回类型,并且是一个永不存在的值(参考).如果方法返回Nothing
,则等效于在该位置引发异常.因此我们可以在这里安全地使用Nothing
,因为每次调用EmptyList.get()
时,编译器都知道这将返回异常.
This implementation doesn't need the parameter T
at all. It just returns the internal object EmptyList
, which itself inherits from List<Nothing>
. The kotlin type Nothing
is the return-type of the throw
keyword and is a value that never exists (reference). If a method returns Nothing
, is is equivalent to throwing an exception at that place. So we can safely use Nothing
here because everytime we would call EmptyList.get()
the compiler knows that this will return an exception.
奖励问题:
来自Java和C ++,我习惯使用ArrayList
或std::vector
来轻松使用该数组.我现在使用kotlin已有几个月了,在编写源代码时,我通常不会在数组和列表之间看到很大的差异.两者都有大量有用的扩展功能,它们的行为类似.但是,由于Java互操作性对于Kotlin团队非常重要,因此Kotlin编译器处理数组和列出的列表非常不同.我通常更喜欢使用列表,这也是我建议您使用的列表.
Coming from Java and C++, I am used to ArrayList
or std::vector
to be far easier to use that arrays. I use kotlin now for a few month and I usually don't see a big difference between arrays and lists when writing source code. Both have tons of usefull extension functions which behave in a similar way. However, the Kotlin compiler handles arrays and lists very different, as Java interoperability is very important for the Kotlin team. I usually prefer using lists, and that's what I'd recommend in your case too.
这篇关于Kotlin泛型阵列T导致“不能将T用作经过类型化的参数".请改用课程"但是List< T>才不是的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!