我有以下特质层次结构。 TraitA
是根特征,并且假设我希望我的数据结构是不可变的,函数commonUpdateFunction()
具有泛型返回类型。我不确定这是不是最好的方法。我还有两个扩展它的特性,增加了两个其他功能。有些类扩展了一个类,有些类扩展了另一个类,但是有些类需要扩展它们。
但是,我现在遇到一个问题,因为那个泛型类型的东西我得到了非法的继承,实际上我只是在将数据结构更新为新的时才得到正确的类型。
此外,由于此泛型类型,我似乎无法将TraitA
作为参数传递。
trait TraitA[T <: TraitA[T]]
{
self : T =>
def commonUpdateFunction() : T
}
trait TraitB extends TraitA[TraitB]
{
def someFunctionB() : Integer = { /// some code }
}
trait TraitC extends TraitA[TraitC]
{
def someFunctionC() : Unit = { /// some code }
}
class ClassB extends TraitB
{
def commonUpdateFunction() : ClassB = { /// some code }
}
class ClassC extends TraitC
{
def commonUpdateFunction() : ClassC = { /// some code }
}
class ClassA extends TraitB with TraitC //**this causes illegal inheritance**
{
def commonUpdateFunction() : ClassA = { /// some code }
}
在具有正确类型的数据结构的不可变更新的同时,在2个特征上实现此继承的正确方法是什么?
答案 0 :(得分:3)
类型参数不是你的问题,问题是ClassA
尝试混合三个commonFunction()
副本,这些副本只有返回类型不同:
class ClassA extends TraitB with TraitC {
def commonFunction() : ClassA = { /// some code }
def commonFunction() : ClassB = { /// some code }
def commonFunction() : ClassC = { /// some code }
}
虽然JVM 允许允许在返回类型上重载,但在编译时不允许这样做 - 混淆的可能性太大(特别是如果涉及类型推断)。
解决方案通常是使用f-bounded多态(就像你对commonUpdateFunction()
所做的那样),但是鉴于所有commonFunction()
定义都是具体的,这里不可能显示如何做到这一点。
看到更多“真实”的代码会有很多帮助!
更新:根据评论中的新信息。
使用抽象类型成员,您可能会发现生活更轻松,而不是类型参数。使用Repr
(用于“Repr”表示)是一种常见的约定,并在集合lib中使用;确保此抽象类型成员具有绑定!
将其他常见属性粘贴在此处:
trait Employee {
type Repr <: Employee
def name : String
def id : Int
def withName(name: String) : Repr
def withId(id: Int) : Repr
}
子特征遵循类似的模式。没有必要重新声明保留其签名的其他抽象成员。您可以在此处细化类型时介绍其他成员。
trait ManagingEmployee extends Employee {
type Repr <: ManagingEmployee
def numberOfReports: Int
def withNumberOfReports(x: Int) : Repr
}
trait SkilledEmployee extends Employee {
type Repr <: SkilledEmployee
def skill: String
}
现在使我们的类型树的叶节点具体化。案例类在这里运作良好,但遗憾的是会有一些重复(宏可能会有所帮助,但这是一个不同的问题)。
请注意类别参数如何使name
和id
具体化,Repr
类型通过=
符号显式化,抽象方法必须是在每个叶类中明确重新定义:
case class HrManager(
name : String,
id : Int,
numberOfReports : Int
) extends ManagingEmployee {
type Repr = HrManager
def withName(name: String) = this.copy(name = name)
def withId(id: Int) = this.copy(id = id)
def withNumberOfReports(x: Int) = this.copy(numberOfReports = id)
}
case class Technician(name: String, id: Int) extends SkilledEmployee {
type Repr = Technician
def withName(name: String) = this.copy(name = name)
def withId(id: Int) = this.copy(id = id)
val skill = "programming"
}
case class TechnicalManager(
name : String,
id : Int,
numberOfReports : Int
) extends SkilledEmployee with ManagingEmployee {
type Repr = TechnicalManager
def withName(name: String) = this.copy(name = name)
def withId(id: Int) = this.copy(id = id)
def withNumberOfReports(x: Int) = this.copy(numberOfReports = id)
val skill = "software architecture"
}