特质和抽象类型

6
假设我有一个基类:
abstract class Base {

  type B<: Base

  def rep:String

  def copy:B
}

class MyBase(override val rep:String) extends Base {
  type B = MyBase

 override def copy = new MyBase(rep)
}

然后我试图添加另一个trait作为mixin,我希望copy的返回类型是适当的类型(也就是调用mixin上的copy方法返回mixin类型,通过将B设置为适当的类型)。我无法使其编译通过,甚至不知道override关键字应该放在哪里。

已编辑:我已经完善了这个例子。

abstract class Base {


  type B <: Base

  def rep:String

  def copy:B

}

class MyBase(val rep:String) extends Base {

  type B = MyBase

  def copy = new MyBase(rep)
}


trait DecBase extends Base {

  abstract override def rep = "Rep: "+super.rep   
}

我的问题是,我该如何为DecBase声明适当的类型B和复制方法,以便复制返回一个DecBase,并且,为什么这个代码无法编译?

println(((new MyBase("ofer") with DecBase)).rep)

这是我在Java中可以实现的东西(使用递归泛型类型有些麻烦)。我相信在Scala中可以做得更好。
编辑:
使用
trait DecBase extends Base {

  override type B = DecBase
  abstract override  val rep= "Dec:"+super.rep
  abstract override def copy = new MyBase(rep) with DecBase
}

我收到了以下编译器错误。
error: overriding type B in class MyBase, which equals com.amadesa.scripts.MyBase;
type B in trait DecBase, which equals com.amadesa.scripts.DecBase has incompatible type
println(((new MyBase("ofer") with DecBase)).rep)

error: overriding type B in class MyBase, which equals com.amadesa.scripts.MyBase;
type B in trait DecBase, which equals com.amadesa.scripts.DecBase has incompatible type
abstract override def copy = new MyBase(rep) with DecBase
3个回答

2
我假设你的混合物看起来像这样:

我假设您的外观混合物类似于此:

trait MixIn extends Base {
  override B = MixinBase
  override def copy = new MixinBase(rep)
}

我认为在MyBase上的override是问题的一部分。它是不必要的,会让编译器困惑。

如果在Base上的copy确实有一个实现,需要使用override,你需要告诉编译器使用哪个方法。如果对编译器来说不是很明显,它会放弃并报错。尝试这样做。

val b = new MyBase(rep) with MixIn {
  override def copy = MixIn.super.copy
}
MixIn.super.copy是你想要调用的函数。
你可能需要查看这个页面:Scala类线性化,了解当你拥有一个方法的竞争实现时会发生什么。
编辑:哦,这是一个完全不同的问题。它是case MyBase(val rep:String)中的val。你不能使用def覆盖val,因为val被认为是不可变的。你可以用val覆盖def或var,但反过来不行。把它改成:
trait DecBase extends Base {
  abstract override val rep = "Rep: "+super.rep
}

请下次附上编译器错误信息,这样可以更轻松地看到问题所在。

再次编辑,这次添加了编译器错误。对我来说,复制方法的正确返回类型很重要。 - user44242
现在我遇到了无法运行的问题。首先,您无法将B覆盖为DecBase,因为DecBase不是MyBase的子类型。但即使解决了这个问题,我仍然收到错误信息。编译器似乎不喜欢覆盖B = MyBase这种类型,但也可能是其他原因。 - sblundy

0

我认为这与MyBase类中的val rep有关。如果您不打算实现def rep,则应将MyBase定义为抽象类。

以下是一个可行的示例:

abstract class Base {
  type B <: Base
  def rep:String
  def copy: B
}

class MyBase(val repVal: String) extends Base {
  type B = MyBase
  def rep = repVal
  def copy = new MyBase(repVal)
}


trait DecBase extends Base {
  abstract override def rep = "Rep: " + super.rep
}

println(((new MyBase("ofer"))).rep) // prints: ofer
println(((new MyBase("ofer") with DecBase)).rep) // prints: Rep: ofer

希望这能有所帮助。

不是的。在Scala中,拥有def或val是可以互换的。val rep的东西是rep的一种实现。 - user44242
抱歉,似乎我忘记了一些基本的东西 :) 谢谢你指出来! - tenshi

0

据我所理解,目标是能够做到:

val myBase: MyBase = new MyBase("alone")
val myBaseCopy: MyBase = myBase.copy

val decBase: DecBase = new MyBase("mixed") with DecBase
val decBaseCopy: DecBase = decBase.copy

让我们重写您的代码,使用类型边界而不是等式在您的type声明中(并且还要修复val repdef rep之间的不匹配,这会隐藏一些其他的编译器错误):

abstract class Base {
  type B <: Base
  def rep: String
  def copy: B
}

class MyBase(_rep: String) extends Base {
  type B <: MyBase
  def rep = _rep
  def copy = new MyBase(rep)
}

trait DecBase extends Base {
  override type B <: DecBase
  override abstract def rep = "Rep: " + super.rep   
}

现在这意味着MyBase.copy应该返回一个MyBase或其子类,而DecBase.copy应该返回一个DecBase或其子类。我相信这就是你想要的,对吧?现在产生的编译器错误就很清楚了:

temp.scala:10: error: type mismatch;
 found   : this.MyBase
 required: MyBase.this.B
  def copy = new MyBase(rep)
             ^
one error found

所以你正在返回一个MyBase,但你真正需要返回子类,例如你想要返回new MyBase(rep) with DecBase而不是new MyBase(rep),但只有当你的对象被声明为new MyBase(...) with DecBase时才这样做。我不知道如何做到这一点,也许你可以看看在对象构造后添加trait


即使我限制为Base和MyBase,并忘记DecBase,它仍无法编译。编译器报错:错误:类型不匹配;找到:com.amadesa.scripts.MyBase,需要:MyBase.this.B。def copy = new MyBase(rep)。 - user44242
1
没错。你希望 DecBase.copy 返回一个 DecBase,但这是不可能的,因为 MyBase 实际上是创建对象的,而且 MyBaseDecBase 一无所知。你期望 DecBase 能够以某种方式将 new MyBase(rep) 改变为 new MyBase(rep) with DecBase - Steve

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接