【发布时间】:2014-02-12 05:56:27
【问题描述】:
我一直试图解决这个问题,但我似乎无法找到解决这个问题的方法。我似乎无法在 Scala 中正确建模。
假设我有一个 trait MyTrait 和一些不可变的类来实现它。
它看起来像这样:
trait MyTrait {
type Repr <: MyTrait
def substitute(original: Item, replacement: Item) : Repr
def substituteAll(
originals: List[Item],
replacement: Item
) : Repr = {
originals match {
case head :: tail => substitute(head).substituteAll(tail, replacement)
case Nil => this //this complains that this is not of type Repr
}
}
}
trait MyTrait2 { ... }
case class MyClassA(originals: List[Item])
extends MyTrait with MyTrait2 {
type Repr = MyClassA
def substitute(original: Item, replacement: Item) : MyClassA = {
//whatever code that updates the list etc.
MyClassA(newOriginals)
}
}
case class MyClassB(originals: List[Item])
extends MyTrait with MyTrait2 {
type Repr = MyClassB
def substitute(original: Item, replacement: Item) : MyClassB = {
//whatever code that updates the list etc.
MyClassB(newOriginals)
}
}
case class CompoundClass(list : List[MyTrait with MyTrait2])
extends MyTrait {
type Repr = CompoundClass
def substitute(
original: Item,
replacement: Item
) : CompoundClass =
CompoundClass(list.map(
myClass => myClass.substitute(original, replacement)
))
)
//the above complains that it is expecting
// List[MyTrait with MyTrait2]
//while in fact it is getting MyTrait2#Repr
}
如果我要总结我的问题,它们会如下:
通过 super-trait 的方法更新不可变类应该返回与实现类相同的类型。
Super-trait 需要能够在有意义的时候返回
this,而不是返回另一个对象。我似乎对此有疑问。我需要能够在不知道实际类型的情况下将超级特征传递给函数。标准多态性。这样该函数就可以调用 trait 的方法,而无需 了解实际的具体类型。
我需要能够使用组合将类组合成其他类。 (想象一个由子表达式组成的表达式)。这似乎是标准组合,但在上述情况下,
#Repr 出现了这些错误
我最初尝试在MyTrait[T] 中使用泛型类型,但这使得无法传递我想要的任何具体类。我现在正在尝试使用抽象类型,我似乎在编译时面临同样的问题。本质上我认为现在真的没有区别,我又陷入了同样的陷阱。
我做错了什么?我看错了吗?
【问题讨论】:
-
乍一看,我怀疑有些你想要的东西是不可能的。但是请查看“F-Bounded Polymophism”(在 Scala 中)以了解允许您实现第一个请求的模式:“通过超级特征的方法更新不可变类应该返回与实现类相同的类型。”
-
@KevinWright 是的,它是对我之前问题的改进。我的方案仍然有一些困难,比前一个更详细,前一个不起作用。
-
@RandallSchulz 我的第一个解决方案是使用 F-Bounded Polymorphism,这就是我对
MyTrait[T]的意图。但是,我遇到了一个问题,即无论我期望MyTrait作为参数,编译器都开始期待[T]的某种类型,结果我一团糟。 KevinWright(在上一个问题中)建议我改用抽象类型成员,这在小示例中似乎效果很好,但实际上我什至无法将this返回到从超类返回此类型成员的函数,并将实例作为参数传递开始得到#Repr -
正如 Randall 所说,对于这些用例,您将需要带有类型参数的完整 F 绑定。您仍然可以通过在层次结构中放置另一层来隐藏参数,但这不是从我的手机上解释的最简单的事情!如果其他人在此期间没有这样做,我会在早上回答。
-
@KevinWright 谢谢。如果您想回答前面的示例问题,那也可以。我不知道为什么我会遇到抽象类型成员的问题,实际上它似乎也遇到了同样的问题。我期待使用
type Repr <: MyTrait并在子类中覆盖它会起作用,但我却得到了这个奇怪的#Repr后缀编译错误。
标签: scala inheritance polymorphism abstract-type