Scala中this.type作类型参数时TreeNode2无法继承TreeNode1如何解决?
解决Scala中TreeNode2作为TreeNode1特例的继承问题
首先得明确为什么你最初的写法行不通:this.type是路径依赖类型,它特指当前实例的类型,而Scala在处理父类继承时,需要的是一个稳定的、可提前确定的类型(比如类本身的类型),此时this还未完成初始化,编译器无法将它作为父类的类型参数传递,所以直接extends TreeNode1[this.type]会报错。
不过我们有两种可行的方案来实现你的需求,让TreeNode2成为TreeNode1的特例,同时简化子类的定义:
方案一:用抽象类型成员替代类型参数
把TreeNode1的类型参数改成抽象类型成员,这样TreeNode2可以在子类中把这个类型绑定到this.type,完美契合你的需求:
// 重构TreeNode1为带抽象类型的版本 trait TreeNode1 { type NodeType def subNodes: List[NodeType] } // TreeNode2作为TreeNode1的特例,固定NodeType为自身类型 trait TreeNode2 extends TreeNode1 { override type NodeType = this.type // 此时subNodes的类型自动变为List[this.type],无需重复定义 } // 子类简化定义,完全符合你的预期 class SomeTreeNode extends TreeNode2 { // 实现subNodes时,返回类型自动是List[SomeTreeNode] override def subNodes: List[SomeTreeNode] = List() }
这个方案的优势是完全贴合你想要的语义:TreeNode2明确是TreeNode1的子类型,同时子类无需再指定类型参数,写法非常简洁。
方案二:保留类型参数,使用F-bounded多态
如果你因为某些原因必须保留TreeNode1的类型参数形式,可以用F-bounded多态来实现近似效果,虽然需要在TreeNode2中引入一个辅助类型参数,但子类的写法依然可以简化:
// 原有的TreeNode1定义 trait TreeNode1[S] { def subNodes: List[S] } // 定义TreeNode2为带F-bounded约束的trait trait TreeNode2[A <: TreeNode2[A]] extends TreeNode1[A] { override def subNodes: List[A] } // 子类定义时,虽然还是要写一次类型参数,但逻辑上和你预期的一致 class SomeTreeNode extends TreeNode2[SomeTreeNode] { override def subNodes: List[SomeTreeNode] = List() }
这种方案的缺点是子类依然需要显式指定类型参数,但好处是兼容你原来的TreeNode1定义,不需要重构它。
总结
如果可以重构TreeNode1,方案一是最优解,它完全满足你“TreeNode2作为TreeNode1特例,子类无需额外类型参数”的需求;如果必须保留原有的TreeNode1结构,方案二可以作为替代。
内容的提问来源于stack exchange,提问作者Evgeny
相关产品推荐
相关产品推荐

