Scala中的存在类型和模式匹配

时间:2011-07-06 19:23:14

标签: scala existential-type

我正在尝试做类似以下的事情:

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
}

如何做我想做的任何想法?

2 个答案:

答案 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 {})
  1. 你肯定想要一个更好的搜索逻辑