首页 文章

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

提问于
浏览
7

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

  • 4

    如果您明确指定exec的type参数,则有效:

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

    似乎是类型推断的限制 .

  • 2

    免责声明:这里不是斯卡拉大师,我写这篇文章 .

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

    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 . 为什么? 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>
    

相关问题