不能将T用作经过类型化的参数

不能将T用作经过类型化的参数

本文介绍了Kotlin泛型阵列T导致“不能将T用作经过类型化的参数".请改用课程"但是List< T>才不是的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个接口,其中包含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类型Nothingthrow关键字的返回类型,并且是一个永不存在的值(参考).如果方法返回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 ++,我习惯使用ArrayListstd::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&lt; T&gt;才不是的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-31 03:56