Scala可堆叠特征和自我类型不兼容类型

时间:2014-03-30 16:24:31

标签: scala typing

我有一个名为Mutatable的特性,它会吐出一个实现类的修改副本。我还有一个特性,我想在它上面堆叠,称为CostedMutatable,它跟踪这样做的成本。 applyMutation方法返回一个Option,后面我想在特定的变异不适用的情况下返回None。

一个简单的版本只适用于Ints(并通过添加新数字“变异”它们)如下所示:

trait Mutatable[M] {

  def applyMutation(mut : M) : Option[this.type]
}

trait CostedMutatable[M] extends Mutatable[M]{

  var cost : Int = _
  def getCostFor(mut : M): Int

  abstract override def applyMutation(mut : M) : Option[this.type] = {
    cost += getCostFor(mut)
    applyMutation(mut)
  }
}

object Example extends App {

  case class Mutation(x: Int)

  class Test(s: Int) extends Mutatable[Mutation] {
    val start = s
    override def applyMutation(mut: Mutation): Option[Test] 
         = Some(new Test(s+mut.x))
  }

  class CostTest(s: Int) extends Test(s) with CostedMutatable[Mutation] {
    override def getCostFor(mut: Mutation): Int = 2
  }

  val testCost = new CostTest(5).cost
}

问题是,这不会编译。我在编译时遇到以下错误:

Error:(23, 18) overriding method applyMutation in trait Mutatable of type (mut: Example.Mutation)Option[Test.this.type];
 method applyMutation has incompatible type
    override def applyMutation(mut: Mutation): Option[Test] = Some(new Test(s+mut.x))
                 ^

除了编译器错误之外,还会想到另一个问题:我是否正确地接近这个问题?我应该使用F-bounded类型吗? (我需要每个新的实现类从applyMutation返回具体实现类的新副本。)

提前致谢。

1 个答案:

答案 0 :(得分:2)

this.type是一种类型,其唯一的实例是thisNothing。当方法返回this.type时,唯一允许的返回值为this。在课程Test中,applyMutation不会返回this,而是返回一个全新的Test,它不是this.type的实例。这就是代码不进行类型检查的原因。

我认为你真正要做的是声明applyMutation返回与this相同的类的值。这样做确实需要F-Bounded多态性。以下是您的代码的重写版本:

trait CostedMutatable[+A <: CostedMutatable[A, M], M] extends Mutatable[A, M] {

  var cost : Int = _
  def getCostFor(mut : M): Int

  abstract override def applyMutation(mut: M): Option[A] = {
    cost += getCostFor(mut)
    super.applyMutation(mut)
  }
}

object Example extends App {

  case class Mutation(x: Int)

  class Test(s: Int) extends Mutatable[Test, Mutation] {
    val start = s
    override def applyMutation(mut: Mutation): Option[Test] 
         = Some(new Test(s+mut.x))
  }

  class CostTest(s: Int) extends Test(s) with CostedMutatable[CostTest, Mutation] {
    override def getCostFor(mut: Mutation): Int = 2
  }

  val testCost = new CostTest(5).cost
}