我正在寻找在数组实例化中提供类清单的建议。我重构了这段代码(编译得很好):
trait Ref[A]
trait Struct[A] {
val arr = new Array[Ref[A]](1)
}
到此:
trait Ref[S <: Sys[S], A]
trait Sys[Self <: Sys[Self]] {
type R[A] <: Ref[Self, A]
}
trait Struct[S <: Sys[S], A] {
val arr = new Array[S#R[A]](1)
}
此操作失败,并显示消息"cannot find class manifest for element type S#R[A]"
那我该怎么解决呢?
答案 0 :(得分:2)
我可以提出一个涉及简单间接的解决方案:
trait Sys[Self <: Sys[Self]] {
type R[A] <: Ref[Self, A]
def newRefArray[A](size: Int): Array[Self#R[A]]
}
trait Struct[S <: Sys[S], A] {
def sys: S
val arr = sys.newRefArray[A](1)
}
答案 1 :(得分:2)
您的问题是Array
在其类型参数中不变,需要一个精确的类型参数。您在type R
中对Sys
的定义仅提供上限。
您可以通过使用相等替换R
的上限来解决定义网站上的问题,
trait Ref[S <: Sys[S], A]
trait Sys[Self <: Sys[Self]] {
type R[A] = Ref[Self, A] // '=' not '<:'
}
trait Struct[S <: Sys[S], A] {
val arr = new Array[S#R[A]](1) // OK
}
或者,如果您希望在R[A]
中打开Sys
,则可以通过细化在用户站点指定等式约束,如此,
trait Ref[S <: Sys[S], A]
trait Sys[Self <: Sys[Self]] {
type R[A] <: Ref[Self, A] // Back to an upper bound
}
trait Struct[S <: Sys[S] { type R[A] = Ref[S, A] }, A] {
// ^^^^^^^^^^^^^^^^^^^^^^^^^
// Assert the equality via a refinement
val arr = new Array[S#R[A]](1) // OK
}
如果您无法通过这两种方式确定type R
,那么您别无选择,只能自己明确提供ClassManifest,
trait Ref[S <: Sys[S], A]
trait Sys[Self <: Sys[Self]] {
type R[A] <: Ref[Self, A]
}
trait Struct[S <: Sys[S], A] {
implicit val rM : ClassManifest[S#R[A]] // Provided manifest later ...
val arr = new Array[S#R[A]](1) // OK
}
class SomeSys extends Sys[SomeSys] {
type R[A] = Ref[SomeSys, A]
}
val s = new Struct[SomeSys, Int] {
val rM = implicitly[ClassManifest[SomeSys#R[Int]]]
// ^^^^^^^^^^^^^^
// Precise type known here
}
选择哪一项很大程度上取决于你的大背景。