假设我在Java中有这个声明,没关系.
abstract class Start<T extends End> {
public T end;
}
abstract class End<T extends Start> {
public T start;
}
Run Code Online (Sandbox Code Playgroud)
然而,在Kotlin中它并不合适,因为Kotlin对"循环"类型参数有限制.
abstract class Start<T : End<*>> {
lateinit var end: T
}
abstract class End<T : Start<*>> {
lateinit var start: T
}
Run Code Online (Sandbox Code Playgroud)
有什么方法可以在Kotlin中解决这个问题,这样我可以拥有相互依赖的泛型类型吗?
不可能只使用一个类型参数.引入Self
类型(在其他一些语言中本机支持)是必要的.但是,在kotlin你必须自己介绍这种Self
类型,因为JetBrains正式拒绝了添加自我类型的请求.
abstract class Start<Self: Start<Self, T>, T: End<T, Self>> {
lateinit var end: T
}
abstract class End<Self: End<Self, T>, T: Start<T, Self>> {
lateinit var start: T
}
Run Code Online (Sandbox Code Playgroud)
PS:这Self
可能会导致繁琐的长型.谨慎行事.
设 G 是一个有向图,其顶点是程序中所有泛型类型声明的所有类型参数。对于 G 中每个类型参数 T 的声明上限集合的 B 闭包中每个类型的构成类型集合中的每个泛型类型 B<...> 中的每个投影类型参数 A,添加一条边T 到 U,其中 U 是对应于类型参数 A 的 B<...> 声明的类型参数。如果图 G 有环,则会出现编译时错误。
\n\n注意:\n图 G 中边 X \xe2\x86\x92 Y 的直观含义是“类型参数 X 的边界的确切含义取决于类型参数 Y 的边界”。
\n\n例子:
\n\n下面的声明是无效的,因为有一条边 T \xe2\x86\x92 T,形成了一个环:
\n\ninterface A<T : A<*>>\n
Run Code Online (Sandbox Code Playgroud)\n\n界限A<*>
是具有隐式界限的投影。如果该界限是明确的,则该类型A<*>
采用等效的形式A<out A<*>>
。以同样的方式,它可以进一步重写为等价的 from A<out A<out A<*>>>
,等等。在其完全展开的形式下,这个界限将是无限的。该规则的目的是避免此类无限类型以及与之相关的类型检查困难。
下面这对声明是无效的,因为有边 T \xe2\x86\x92 S 和 S \xe2\x86\x92 T,形成一个环:
\n\ninterface B<T : C<*>>\ninterface C<S : B<*>>\n
Run Code Online (Sandbox Code Playgroud)\n\n下面的声明是无效的,因为有边 K \xe2\x86\x92 V 和 V \xe2\x86\x92 K,形成一个环:
\n\ninterface D<K: D<K, *>, V: D<*, V>>\n
Run Code Online (Sandbox Code Playgroud)\n\n另一方面,以下每个声明都是有效的:
\n\ninterface A<T : A<T>>\ninterface D<K, V : D<*, V>>\n
Run Code Online (Sandbox Code Playgroud)\n\nTODO:这些算法与灵活类型的交互。TODO:导入在 Java 中声明的违反这些规则的类型。
\n\n子类型关系是归纳决定的,即必须有有限的证明。
\n\ninterface N<in T>\ninterface A<S> : N<N<A<A<S>>>>\n
Run Code Online (Sandbox Code Playgroud)\n\n\n