【问题标题】:Kotlin class hierarchy and (co)varianceKotlin 类层次结构和(协)方差
【发布时间】:2021-03-19 21:15:03
【问题描述】:

在我的设置中,我试图拥有一个继承自 Map 的接口 Table(因为它主要用作地图的包装器)。两个类继承自 Table - 本地和全局。全局的将有一个可变映射,而本地的将只有一个本地条目的映射。

// entries
sealed class Entry {
    class EntryLocal : Entry
    class EntryGlobal : Entry
}

interface Table : Map<String, Entry> {
    fun getRecursive(key: String): Entry?   
}

class GlobalTable(val map:MutableMap<String, Entry>) : Table, Map<String, Entry> by map {
    override fun getRecursive(key: String) = this[key]

    ...
}

class LocalTable(
    private val parent: Table,
    val map: Map<String, EntryLocal>
) : Table, Map<String, EntryLocal> { // gives error
    override fun getRecursive(key: String): Entry? = map[key] ?: parent.getRecursive(key)

}

我收到以下错误:

Type parameter V of 'Map' has inconsistent values: Entry, EntryVar

这是为什么呢? Map&lt;String, EntryLocal&gt;不是继承自Map&lt;String, Entry&gt;吗?

【问题讨论】:

    标签: kotlin generics covariance


    【解决方案1】:

    你说得对,Map 的值类型是协变的,所以 Map&lt;String, EntryLocal&gt;Map&lt;String, Entry&gt;

    但是,这不是您的问题。问题是LocalTable 继承自Map&lt;String, EntryLocal&gt;(直接)和Map&lt;String, Entry&gt;(通过Table),所以不清楚LocalTable 中的值类型应该是什么。

    也就是说LocalTable.get的返回类型是什么?是Entry 还是EntryLocal

    简而言之就是这个问题:

    interface M<T> {}
    interface A : M<String> {}
    interface B : M<Object> {}
    class C : A, B {}
    

    你会得到同样的错误,说M 的参数T 的值不一致。即使StringObject,Kotlin 也不会假定基类M 的类型参数T 因此应该是String(或Object)。

    【讨论】:

    • 谢谢!我希望它得到支持——我不明白为什么它会给编译器带来麻烦。另外,上面的编译吗?我认为 Kotlin 不支持类的多重继承(它可以与接口一起使用)
    • 说除了你得到的错误之外,“只有一个类可能出现在超类型列表中”。但你是对的,使用接口的例子会更清楚!
    • 您可以通过将 Table 的 Key 类型设置为 T 其中 T: Entry 来使其工作,但是您将无法将 LocalTable 的父级设置为 LocalTable,否则 parent.getRecursive(key) 将不会t 返回一个 EntryLocal。
    • 没关系 - LocalTable::getRecursive 无论如何都会返回一个条目(因为它取决于父母,可能是 GlobalTable
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-08
    • 2010-09-27
    相关资源
    最近更新 更多