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

时间:2013-01-11 13:12:11

标签: scala types type-parameter

我无法理解为什么我得到“推断类型参数不符合类型参数边界”。 首先,我定义了一个名为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]的类型参数?

2 个答案:

答案 0 :(得分:4)

如果您明确指定exec的类型参数,则可以使用:

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

似乎是类型推断的限制。

答案 1 :(得分:3)

免责声明:这里不是scala guru,我正在学习它,因为我正在写这个

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

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参数,但拒绝仅Bar扩展Foo的{​​{1}}。为什么? 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>