几个斯卡拉特性相互作用,给这种行为。首先,Manifest
不仅附加到构造函数的隐式隐式参数列表中,还附加在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 m
s都是由th创建的e编译器并通过隐式参数列表发送给该方法。
只要有人在编译器知道Foo
的类型参数的地方使用copy
方法,就可以。例如,这将工作外的酒吧类:
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
类,因为第二个特点的:而Bar
类型参数的Bar
类中已知的类型,参数类型参数不是。它知道在Bar
中的A
是Foo
或SubFoo
或SubSubFoo
,但是如果它是Foo[Int]
或Foo[String]
则不是。当然,这是Scala中众所周知的类型擦除问题,但即使看起来类似于类型foo
的类型参数,也会出现问题。但是,请记住,每次调用copy
时都会有一个秘密注入清单,这些清单会覆盖之前存在的清单。由于Bar
类没有想法的foo
类型参数,它只是创造了Any
清单,并将沿着这样的:
def fooCopy = foo.copy()(manifest[Any])
如果一个人在Foo
类控制(例如,它不List
),那么一个变通办法,通过添加一个方法在做的所有复制的Foo类,将做适当的复制,像localCopy
以上,并返回结果:
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
干得好,我的朋友! – 2012-08-12 08:04:49