特征和抽象类型

时间:2011-02-01 15:30:43

标签: scala

假设我有一个基类

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)
}

然后我尝试添加另一个特性作为mixin,我希望复制的返回类型是合适的类型(意味着在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 个答案:

答案 0 :(得分:2)

我认为你的混音看起来像这样

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

我认为override上的MyBase是问题的一部分。这是不必要的,并使编译器感到困惑。

如果copy Base实际上有一个实现,需要override,你需要告诉编译器使用哪种方法。如果它不明显,它会抛出手并引发错误。试试这个。

val b = new MyBase(rep) with MixIn {
  override def copy = MixIn.super.copy
}

MixIn.super.copy是对您想要的人的调用。

您可能希望在Scala Class Linearization上查看此页面,以了解当您在某种类型中对方法进行竞争实施时会发生什么。

编辑:哦,这是一个完全不同的问题。它是case MyBase(val rep:String)中的val。您不能使用def覆盖val,因为假定val是不可变的。您可以使用val覆盖def或var,但不能反过来。成功:

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

下次请包含编译错误。它使得查看问题变得容易得多。

答案 1 :(得分:0)

我认为它在某种程度上与班级val rep中的MyBase相关联。如果您不打算实施MyBase,则应定义def rep摘要。

以下是工作示例:

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

希望这有帮助。

答案 2 :(得分: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时。我不知道如何做到这一点,不过你可能会看adding a trait after an object has been constructed