Scala Stackable Trait 和 Self Type 不兼容类型

标签 scala typing

我有一个称为 Mutatable 的特征,它会生成一个实现类的修改副本。我还想在其之上添加一个称为 CostedMutatable 的特征,它可以跟踪这样做的成本。 applyMutation 方法返回一个 Option,稍后我想在特定突变不适用的情况下返回 None。

仅适用于整数(并通过添加新数字来“改变”它们)的简单版本如下所示:

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 边界类型吗? (我需要每个新的实现类从 applyMutation 返回具体实现类的新副本。)

提前致谢。

最佳答案

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
}

关于Scala Stackable Trait 和 Self Type 不兼容类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22746471/

相关文章:

python - 我可以使用 python 装饰器根据输入类型预处理输入和后处理输出吗?

scala - 无法使用 Akka-Http 验证 OAuth2

scala - 如何函数式地编写 Scala 的 Either

multithreading - 获取任务节点执行器核心数的方法?

python - 如何动态使用Python的类型提示来指示返回值与参数类型相同

python - 在编写 python 类型注释时处理 79 个字符的限制

java - 嵌入式 Kafka 用于无 Spring 测试

scala - Monix 并行任务上的错误处理(使用 parMap)

python - 运行时错误 : Expected object of scalar type Long but got scalar type Float for argument #2 'mat2' how to fix it?

python输入: Is it possible to specify the type of a variable later than at its creation?