3

オブジェクトを初期化し、そのオブジェクトを再度使用して追加の操作を行う Factory に要約するコードがあります。

trait Factory[T] {
  def initialize(): T;

  def finish(t: T): Unit;
}

私がこれを理解しているように、 の結果は、 に関係なく、常に任意の 1 つのインスタンスにinitialize渡すのに適している必要があります。finishFactoryT

ファクトリ自体は、何が何であるかわからない時点で呼び出されますT

object Minimal {
  object StringFactory extends Factory[String] {}
  val factories = Map[Int, Factory[_]](0 -> StringFactory)

  val factory = factories(0)

  // (1)
  val obj = factory.initialize()
  factory.finish(obj)

  // (2)
  def wrapper[T](factory: Factory[T]): Unit = {
    val obj = factory.initialize()
    factory.finish(obj)
  }
  wrapper(factory)
}

バリアント (2) は機能しますが、バリアント (1) は機能しません。

type mismatch; found : Minimal.obj.type (with underlying type Any) required: _$6

しかし、これを修正する方法がわかりません。それは可能ですか?

コンパイラは、wrapperそれ自体を理解できないメソッドを呼び出すことによって何を得ますか? 私の観点からobjする_$6と、コンパイラはそのキャプチャに_. まったく新しいメソッドを導入することなく、コンパイラにそれを認識させるにはどうすればよいですか?

4

3 に答える 3

3

存在型はその存在性を失い、そのインスタンスを val 自体に割り当てた後に上限になります。

 scala> trait Factory[T] { type TT = T; def initialize(): TT; def finish(t: TT): Unit;}
 defined trait Factory

 scala> val factory: Factory[_] = new Factory[Int] {def initialize = 5; def finish(t: Int) {}}
 factory: Factory[_] = $anon$1@31d0ca61

 scala> factory.finish(factory.initialize())

これは機能しません:

scala> val obj = factory.initialize()
obj: Any = 5

scala> factory.finish(obj)
<console>:11: error: type mismatch;
 found   : Any
 required: factory.TT
    (which expands to)  _$1
              factory.finish(obj)
                             ^

そして、これは、scala がそれらの型を等しいと見なさないため (両方が同じ型メンバーでない限り)、存在intialize()性は Any の任意のサブクラスを返す可能性があることを意味し、Any のfinish()任意の (しかし常に同じであるとは限らない) サブクラスを受け入れる可能性があるためです。

scala> trait Factory[T] { def initialize(): T; def finish(t: T): Unit;}
defined trait Factory

scala> val factory: Factory[_] = new Factory[Int] {def initialize = 5; def finish(t: Int) {}}
factory: Factory[_] = $anon$1@6e5da49

scala> factory.finish(factory.initialize())
<console>:10: error: type mismatch;
 found   : (some other)_$1(in value factory)
 required: _$1(in value factory)
              factory.finish(factory.initialize())
                                               ^

したがって、ここで入力と出力をバインドする唯一の方法は、それらの間で型メンバーを共有することです。

于 2015-01-15T09:28:48.600 に答える
1

Régis' answerに基づいて、コンパイラが推論することがわかりましたobj: Factory.T。そこから、これを使用するdk14 の提案type TT = Tと組み合わせるのは小さな一歩でした。結果はこれですが、ラッパーメソッドを導入することなく、ジェネリックで静的に型チェックされます。両方に称賛を!

元の質問に文字通り答えるには

私の観点からは、obj の型は _$6 である必要があります。これは、コンパイラが _ のキャプチャに名前を付けているように見えるためです。まったく新しいメソッドを導入することなく、コンパイラにそれを認識させるにはどうすればよいですか?

_$6明示的な名前を与えることによってTT。もちろん、メソッドもその名前を使用する必要があります。

trait Factory[T] {
  type TT = T
  def initialize(): TT;

  def finish(t: TT): Unit;
}

object Minimal {
  object StringFactory extends Factory[String] {
    def initialize(): TT = ""
    def finish(t: TT): Unit = {}
  }
  val factories = Map[Int, Factory[_]](0 -> StringFactory)

  val factory = factories(0)

  // (1)
  val obj: factory.TT = factory.initialize()
  factory.finish(obj)

  // (2)
  def wrapper[T](factory: Factory[T]): Unit = {
    val obj = factory.initialize()
    factory.finish(obj)
  }
  wrapper(factory)
}
于 2015-01-15T10:03:40.033 に答える