Kotlin:如果 E 是实现接口 I 的枚举 class,则从具有 return 类型 Array<I> 的函数返回 Array<E>

Kotlin: Returning Array<E> from function with return type Array<I> if E is enum class that implements interface I

最近我 运行 遇到一个问题,我有一个函数必须 return 一个 I 的数组,以枚举 E 的所有值的形式,E 实现接口 I,我想到的每个代码编译器都抱怨类型不匹配:

Error:(x, x) Kotlin: Type mismatch: inferred type is Array<E> but Array<I> was expected

一个最小的例子:

    interface I {}
    enum class E: I {
        A, B, C;
    }
    fun getMoreInterfaces(): Array<I> {
        return E.values()
    }

尝试将 E.values() 分配给 Array<I> 类型的变量时会发生这种情况 我很肯定这应该是可能的,因为 E 实现了 I.

我在测试时想到的另一件事是它在像这样使用时工作得很好:

    interface I {}
    enum class E: I {
        A, B, C;
    }
    fun getMoreInterfaces(): Array<I> {
        return arrayOf(E.A, E.B, E.C)
    }

我就这个主题进行了很多搜索,但没有成功(也许我选择了错误的描述方式?)

在 Kotlin 中,不像 Java,Array<T>T 上是不变的,因此,对于 I 的子类型 EArray<E>Array<I> 不是彼此的子类型。参见:Variance.

鉴于 Array<T> 类型也存储项目类型并且不能完全 unchecked casts,解决此问题的最佳方法是创建一个单独的数组。

您可以通过手动创建数组并用项目填充它来做到这一点,就像在您的示例中一样(或使用构造函数 Array(n) { ... }), or use .toTypedArray() applied to the list representation of the array (.asList()):

fun getMoreInterfaces(): Array<I> {
    return E.values().asList().toTypedArray()
}

(runnable sample)

但基本上,如果您不在性能关键代码中,您可以直接使用 List<I>,这对于 Kotlin 来说比使用数组更惯用,也更简单。

另请参阅:

Array 是 Kotlin 中的不变泛型,所以如果你需要 return Array<I> 的一个实例,你不能 return Array<E> 相反,即使 EI.

的子类型

但如果您仅 使用 数组中的 return 值,则可以将其类型声明为 Array<out I>。此类型是 Array<I> 类型的协变投影,它允许您 return 同时 Array<I>Array<E>.

interface I {}
enum class E: I {
    A, B, C
}
fun getMoreInterfaces(): Array<out I> {
    return E.values()
}