Kotlin泛型类层次编译报错:StrEdge不符合Edge<String, StrEdge>边界
问题原因
StrEdge继承自WeightedEdgeImpl<String>,而WeightedEdgeImpl<String>实现的是WeightedEdge<String, WeightedEdgeImpl<String>>,对应Edge<String, WeightedEdgeImpl<String>>。但Graph<N, E>要求E必须是Edge<N, E>,也就是对于StrGraph来说,E需要满足Edge<String, StrEdge>。当前StrEdge并没有直接实现Edge<String, StrEdge>,而是间接实现了Edge<String, WeightedEdgeImpl<String>>,因此编译器判定类型参数不满足约束。
解决方案
方案一:调整WeightedEdgeImpl的泛型定义,支持子类自引用
修改WeightedEdgeImpl为带自引用泛型的类,让子类可以将自身作为泛型参数传入,从而满足Edge的约束:
interface Edge<N:Any, E:Edge<N,E>> { val from: N val to: N fun copy(f: N = from, t: N = to): E } interface WeightedEdge<N:Any,E: WeightedEdge<N, E>> : Edge<N, E> { val weight: Int } // 修改WeightedEdgeImpl,添加自引用泛型E open class WeightedEdgeImpl<N:Any, E: WeightedEdgeImpl<N, E>>( override val from: N, override val to: N, override val weight: Int ) : WeightedEdge<N, E> { // 让子类实现copy方法 abstract override fun copy(f: N, t: N): E } class StrEdge(from: String, to: String, weight: Int) : WeightedEdgeImpl<String, StrEdge>(from, to, weight) { override fun copy(f: String, t: String): StrEdge { return StrEdge(f, t, weight) } } interface Graph<N:Any, E: Edge<N,E>> { } class StrGraph : Graph<String, StrEdge> { }
方案二:让StrEdge直接实现目标接口并委托给WeightedEdgeImpl
通过委托模式复用WeightedEdgeImpl的实现,同时让StrEdge直接实现WeightedEdge<String, StrEdge>,满足Graph的约束:
interface Edge<N:Any, E:Edge<N,E>> { val from: N val to: N fun copy(f: N = from, t: N = to): E } interface WeightedEdge<N:Any,E: WeightedEdge<N, E>> : Edge<N, E> { val weight: Int } open class WeightedEdgeImpl<N:Any>( override val from: N, override val to: N, override val weight: Int ) : WeightedEdge<N,WeightedEdgeImpl<N>> { override fun copy(f: N, t: N): WeightedEdgeImpl<N> { return WeightedEdgeImpl(f, t, weight) } } // 直接实现WeightedEdge<String, StrEdge>,并委托给WeightedEdgeImpl class StrEdge( private val delegate: WeightedEdgeImpl<String> ) : WeightedEdge<String, StrEdge> by delegate { // 提供构造函数兼容原用法 constructor(from: String, to: String, weight: Int) : this(WeightedEdgeImpl(from, to, weight)) override fun copy(f: String, t: String): StrEdge { return StrEdge(f, t, delegate.weight) } } interface Graph<N:Any, E: Edge<N,E>> { } class StrGraph : Graph<String, StrEdge> { }
两种方案都能解决编译错误,方案一更贴近原有的继承结构,方案二通过委托避免了修改父类的泛型定义,适合不想改动原有WeightedEdgeImpl的场景。
内容的提问来源于stack exchange,提问作者ModdyFire
相关产品推荐
相关产品推荐

