いくつかの Scala の特性が相互作用して、この動作を実現します。まず、Manifests がコンストラクターの秘密の暗黙パラメーター リストに追加されるだけでなく、copy メソッドにも追加されることです。ことはよく知られている.
case class Foo[+A : Manifest](a: A)
は単なるシンタックスシュガーです
case class Foo[+A](a: A)(implicit m: Manifest[A])
ただし、これはコピー コンストラクターにも影響します。これは次のようになります。
def copy[B](a: B = a)(implicit m: Manifest[B]) = Foo[B](a)(m)
これらすべてのimplicit ms はコンパイラによって作成され、暗黙的なパラメーター リストを介してメソッドに送信されます。
コンパイラが型パラメータcopyを知っている場所でメソッドを使用している限り、これは問題ありません。Fooたとえば、これは Bar クラスの外で機能します。
val foo = Foo(1)
val aCopy = foo.copy()
println(aCopy.myManifest) // Prints "Int"
これが機能するのは、コンパイラがそれfooが であると推測し、それが であるFoo[Int]ことがわかっているfoo.aためIntですcopy。
val aCopy = foo.copy()(manifest[Int]())
manifest[T]()(は、型のマニフェスト表現を作成する関数であることに注意してください。TたとえばManifest[T]、大文字の「M」を使用します。デフォルト パラメータの への追加は示されていません。)渡されたマニフェストが既にあるため、クラスcopy内でも機能します。Fooクラスが作成されたとき。次のようになります。
case class Foo[+A : Manifest](a: A) {
def myManifest = implicitly[Manifest[_ <: A]]
def localCopy = copy()
}
val foo = Foo(1)
println(foo.localCopy.myManifest) // Prints "Int"
ただし、元の例ではBar、2 番目の特殊性のためにクラスで失敗します。クラスBar内での型パラメーターは認識されBarていますが、型パラメーターの型パラメーターは認識されていません。AinBarが aFooまたは aSubFooまたはであることは認識していますが、 aまたはa である場合は認識してSubSubFooいません。もちろん、これは Scala でよく知られている型消去の問題ですが、クラスがs 型パラメーターの型で何もしていないように見える場合でも、ここでは問題として現れます。ただし、呼び出されるたびにマニフェストの秘密の注入があり、それらのマニフェストは以前にあったものを上書きすることを覚えておいてください。クラスにはわからないので、の型パラメーターでしたFoo[Int]Foo[String]foocopyBarfooつまり、次のようにマニフェストを作成してAny送信するだけです。
def fooCopy = foo.copy()(manifest[Any])
クラスを制御できる場合Foo(たとえば、 ではない場合List)、上記のように適切なコピーを実行しlocalCopy、結果を返すメソッドを追加して、Foo クラスですべてのコピーを実行することにより、1 つの回避策を実行します。
case class Bar[A <: Foo[Any]](foo: A) {
//def fooCopy = foo.copy()
def fooCopy = foo.localCopy
}
val bar = Bar(Foo(1))
println(bar.fooCopy.myManifest) // Prints "Int"
Foo別の解決策は、 s 型パラメーターを のマニフェスト型パラメーターとして追加することBarです。
case class Bar[A <: Foo[B], B : Manifest](foo: A) {
def fooCopy = foo.copy()
}
ただし、クラス階層が大きい場合 (つまり、より多くのメンバーが型パラメーターを持ち、それらのクラスにも型パラメーターがある場合)、すべてのクラスがその下のすべてのクラスの型パラメーターを持つ必要があるため、これはうまくスケーリングしません。また、次のように構築しようとすると、型推論が狂ってしまうようBarです。
val bar = Bar(Foo(1)) // Does not compile
val bar = Bar[Foo[Int], Int](Foo(1)) // Compiles