如何解决Kotlin中有限束限制的违反?

fik*_*r4n 8 generics kotlin

假设我在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中解决这个问题,这样我可以拥有相互依赖的泛型类型吗?

gle*_*e8e 9

不可能只使用一个类型参数.引入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可能会导致繁琐的长型.谨慎行事.


Muz*_*ain 5

设 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\n
interface A<T : A<*>>\n
Run Code Online (Sandbox Code Playgroud)\n\n

界限A<*>是具有隐式界限的投影。如果该界限是明确的,则该类型A<*>采用等效的形式A<out A<*>>。以同样的方式,它可以进一步重写为等价的 from A<out A<out A<*>>>,等等。在其完全展开的形式下,这个界限将是无限的。该规则的目的是避免此类无限类型以及与之相关的类型检查困难。

\n\n

下面这对声明是无效的,因为有边 T \xe2\x86\x92 S 和 S \xe2\x86\x92 T,形成一个环:

\n\n
interface 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\n
interface D<K: D<K, *>, V: D<*, V>>\n
Run Code Online (Sandbox Code Playgroud)\n\n

另一方面,以下每个声明都是有效的:

\n\n
interface A<T : A<T>>\ninterface D<K, V : D<*, V>>\n
Run Code Online (Sandbox Code Playgroud)\n\n

TODO:这些算法与灵活类型的交互。TODO:导入在 Java 中声明的违反这些规则的类型。

\n\n

子类型关系是归纳决定的,即必须有有限的证明。

\n\n
interface N<in T>\ninterface A<S> : N<N<A<A<S>>>>\n
Run Code Online (Sandbox Code Playgroud)\n\n

官方链接

\n