理解Scala中“推断的类型参数不符合类型参数边界”的错误



我不明白为什么我得到一个"推断的类型参数不符合类型参数界限"。首先,我定义了一个称为CS的特性,它可以由几个类(例如,CS01和CS02(实现:

trait CS[+T <: CS[T]] {
  this: T =>
  def add: T
  def remove: T
}
class CS01 extends CS[CS01] {
  def add: CS01 = new CS01
  def remove: CS01 = new CS01
}
class CS02 extends CS[CS02] {
  def add: CS02 = new CS02
  def remove: CS02 = new CS02
}

其思想是在CS01和CS02上调用addremove时保持实现的类型。其次,我想定义可以在符合特征CS的每个类上执行的操作。然后,我定义了一个称为Exec的特征(Exec01Exec02类的两个非常简单的例子混合了Exec特征(:

trait Exec {
  def exec[U <: CS[U]](x: U): U
}
class Exec01 extends Exec {
  def exec[U <: CS[U]](x: U): U = x.add
}
class Exec02 extends Exec {
  def exec[U <: CS[U]](x: U): U = x.remove
}

再次,我需要保留混合了CS特性的类的已实现类型。这就是为什么exec被[U <: CS[U]]参数化的原因。

最后,我希望任何对其启用操作的CS都能混合特征Executable,从而可以执行特征Exec:之后的操作

trait Executable[T <: CS[T]] {
  this: T =>
  def execute(e: Exec): T = e.exec(this)
}

然而,当我试图编译时,我得到了以下错误:

error: inferred type arguments [this.Executable[T] with T] do not conform to method exec's type parameter bounds [U <: this.CS[U]]
  def execute(e: Exec): T = e.exec(this)
                              ^

我不太理解,因为任何混合了Executable的类都必须是T类型,并且由于trait Executable[T <: CS[T]]中的绑定而限制了CS特性的混合。那么,为什么this不符合类型参数绑定的U <: CS[U]呢?

如果明确指定要执行的类型参数,则有效:

def execute(e: Exec): T = e.exec[T](this)

似乎是类型推理的一个限制。

免责声明:这里不是scala大师,我在写这篇文章时正在学习它

首先,让我们简化这个例子。

scala> trait Moo[+X <: Moo[X]] 
defined trait Moo
scala> class Foo extends Moo[Foo]
defined class Foo
scala> def foobar[U <: Moo[U]](x: U) = x
foobar: [U <: Moo[U]](x: U)U
scala> foobar(new Foo)
res0: Foo = Foo@191275b
scala> class Bar extends Foo
defined class Bar
scala> foobar(new Bar)
<console>:12: error: inferred type arguments [Bar] do not conform to method 
foobar's type parameter bounds [U <: Moo[U]]
              foobar(new Bar)
              ^
scala> 

foobar接受Foo变元,但拒绝仅扩展FooBar。为什么?foobar是一个泛型,根据其参数的类型进行参数化。它在类型的上强加了一个绑定。类型推理器不会检查参数类型的每一个祖先,希望找到一个满足约束的祖先。

那么,如何将绑定强加给祖先类型呢?一种方法是存在类型。

scala> def foobar[V <: Moo[U] forSome {type U}](x: V) = x
foobar: [U <: Moo[_], V <: U](x: V)V
scala> foobar(new Foo)
res3: Foo = Foo@1154718
scala> foobar(new Bar)
res4: Bar = Bar@5a7ff7
scala> 

最新更新