我正在尝试做类似以下的事情:
trait MyData
trait MyId
trait MyDataType[T <: MyData] {
type MyIdType <: MyId
// There can be converters here to bring back
// lost type information.
}
trait Writer[T <: MyData] {
def save(data: Map[T#MyIdType, T])
}
val writers: Map[MyDataType[_ <: MyData], Writer[_ <: MyData]]
val data: Map[MyDataType[_ <: MyData], Map[MyId, MyData]]
// mapping from id -> data grouped by the type of data.
// We've now lost the type safety since this is just a big bag.
data.foreach { case (type, map) =>
writer.get(type).save(map)
// DOES NOT COMPILE SINCE IT CAN'T GUARANTEE WRITER AND
// MAP ARE OF SAME TYPE
}
我想将此更改为
data.foreach {
case (type: MyDataType[T], map: Map[T#MyIdType, T]) forSome {
type T <: MyData } =>
// do save logic
// COMPILER COMPLAINS - not found: type T
}
但看起来我不能在case语句中使用存在类型。请注意,此时我并不关心缺少类型安全性,因为我的数据已经按类型分组,因此我只想要一种方法来强制编译器接受类型I。有什么建议?我也试图参数化一个案例陈述,但那是不行的:
data.foreach {
case [T <: MyData](type: MyDataType[T], map: Map[T#MyIdType, T]) =>
// do save logic
// COMPILER COMPLAINS -
// illegal start of simple pattern for the parameterization
}
如何做我想做的任何想法?
答案 0 :(得分:0)
我很想说,即使你的问题有一个解决方案,你的设计中也有一些听起来不对的东西。一方面,您使用的复杂类型对于编译时的类型安全和推理非常有用。另一方面,您使用地图存储运行时信息。所以要么你要简化你的特性而忘记type-saftey,要么忘记在运行时在地图中存储类型。
例如,如果要将编写器与特定的MyData子类关联,则可以使用类型类,这些类是灵活的并在编译时解析。
答案 1 :(得分:0)
这是你想要的吗?
trait MyData
trait MyId
trait Writer[T <: MyData] {
def save(data: T)
}
var writers: Map[Manifest[_ <: MyData], Writer[MyData]] = Map.empty
var data: Map[MyId, (MyData, Manifest[_ <: MyData])] = Map.empty
data.foreach {
case (id, (d, m)) =>
writers.get(m).map(_.save(d)) // [1]
}
def addData[T <: MyData](id: MyId, d: T)(implicit m: Manifest[T]) = {
data += ((id, (d, m)))
}
// you don't need to give the m parameter, it is given by the compiler
addData(new MyId {}, new MyData {})