幾個斯卡拉特性相互作用,給這種行爲。首先,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