9

「推論された型引数が型パラメーターの境界に準拠していません」というメッセージが表示される理由がわかりません。最初に、いくつかのクラス (CS01 と CS02 など) で実装できる CS というトレイトを定義しました。

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 を呼び出すとき、addまたはremoveCS01 と CS02 で実装された型を保持することです。次に、特性 CS に準拠するすべてのクラスで実行できる操作を定義したいと思います。次に、という名前のトレイトを定義しましたExec(2 つの非常に単純なクラスの例とExec01トレイトExec02の mixinを使用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]]ます。

最後に、それに対する操作を有効にして、 traitに続く操作を実行できるようにするCStrait を mixin する必要があります。ExecutableExec

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)
                              ^

混合するクラスは、バインドされているため、 CS トレイトの mixin の制約を持つExecutable型でなければならないため、よくわかりません。では、なぜ型パラメーター bound に準拠しないのでしょうか?Ttrait Executable[T <: CS[T]]thisU <: CS[U]

4

2 に答える 2

5

type パラメーターを exec に明示的に指定すると機能します。

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

型推論の制限のようです。

于 2013-01-11T14:38:37.540 に答える
4

免責事項: ここではスカラの第一人者ではありません。これを書いているときに学んでいます。

まず、例を単純化しましょう。

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の a を拒否します。なんで?引数の型によってパラメータ化されたジェネリックです。そのタイプに境界を課します。型推論は、境界を満たすものを見つけようとして、引数の型のすべての先祖をチェックするわけではありません。BarFoofoobar

では、祖先型に境界を課すにはどうすればよいでしょうか。1 つの方法は、存在型を使用することです。

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> 
于 2013-01-11T14:13:10.480 に答える