我在 Kotlin 中组合子类化多态性和泛型(临时多态性)时遇到了问题。
这是我的类型定义:
interface State
interface StatefulContainer<out S : State> {
val state: S
}
interface StatefulContainerRepository<C: StatefulContainer<S>, S: State>
// Specialization starts here
sealed interface MyState : State
enum class StateA : MyState { A1, A2 }
enum class StateB : MyState { B1, B2 }
sealed interface MyEntity : StatefulContainer<MyState> {
override val state: MyState
}
data class EntityA(override val state: StateA) : MyEntity
data class EntityB(override val state: StateB) : MyEntity
sealed interface MyContainerRepository<C: StatefulContainer<S>, S: MyState>: StatefulContainerRepository<C, S>
class ARepository: MyContainerRepository<EntityA, StateA>
类型检查器返回以下错误:
Type argument is not within its bounds. Expected: StatefulContainer<StateA>. Found: EntityA
。这很奇怪,因为EntityA
是一个StatefulContainer<StateA>
——至少我是这么认为的。但是,如果我进行以下修改:
data class EntityA(override val state: StateA) : MyEntity, StatefulContainer<StateA>
类型检查器抱怨
Type parameter S of 'StatefulContainer' has inconsistent values: MyState, StateA
。为什么会这样呢?如何正确输入上面的类层次结构?
我习惯了 Haskell 等语言的更直接的参数多态性,或者纯 OO 子类型。这里的组合,再加上 JVM 的类型擦除,让我很难理解发生了什么。因此,除了上面的具体问题之外,我还希望获得一些更基本的见解 - 哪些概念在起作用,如果我设法理解它们,将帮助我解决这个问题和类似的情况?
这很奇怪,因为
是EntityA
。StatefulContainer<StateA>
这不是真的。
EntityA
是一个MyEntity
,而那只是一个StatefulContainer<MyState>
,你希望它比实际情况更具体。只有以下内容才有效:
class ARepository: MyContainerRepository<EntityA, MyState>
或者,您可以通过另一种方式声明
EntityA
。你建议这个:
data class EntityA(override val state: StateA) : MyEntity, StatefulContainer<StateA>
但这也不起作用,因为
StatefulContainer<StateA>
与 MyEntity
不兼容。他们的属性不匹配。让我们看看如果上述方法可行会发生什么。为了更好地演示它,我们首先让 MyEntity
将其属性覆盖为 var
而不是 val
(*):
override var state: MyState
然后考虑这段代码:
val entityA: StatefulContainer<StateA> = EntityA(StateA.A1)
val myEntity: MyEntity = entityA
myEntity.state = StateB.B1
首先,我们创建 EntityA 的一个新实例,然后将其转换为
MyEntity
。通过上面的 EntityA
声明,应该可以正常工作,因为它具有 MyEntity
和 StatefulContainer<StateA>
两种类型。前两行很好。然后让我们看最后一行:乍一看一切似乎都正常:我们更改 state
的 MyEntity
值并将其设置为允许的子类型之一。但请记住,底层对象实际上是 EntityA
的实例。并且 都不允许其值被更改(它被声明为 val
),nor 也不能保存 StateB.B1
(因为它是 StateA
类型)。这里出了严重的问题。上面的代码没有错误,所以它一定是EntityA
的声明:它显然不可能同时是MyEntity
和aStatefulContainer<StateA>
。
只需删除
MyEntity
作为 EntityA
的子类型,如下所示:
data class EntityA(override val state: StateA) : StatefulContainer<StateA>
现在您的初始代码将按预期工作。
(*):这是完全合法的,因为通过覆盖它会创建一个新属性,该属性可以具有任何特征,只要它具有also来自超类的特征。