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

Scala中的存在类型与模式匹配,scala,existential-type,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,

我试着做一些大致如下的事情:

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
}
trait MyData
特征粘虫

特征MyDataType[T我想说的是,即使你的问题有了解决方案,你的设计中也有一些听起来不正确的地方。一方面,你使用复杂类型,这对类型安全和编译时的推理很好。另一方面,你使用映射来存储运行时信息。因此,你要么简化你的特性,要么忘记t type saftey,或者您忘记了在运行时将类型存储在映射中


例如,如果您想将一个writer与一个特定的MyData子类相关联,您可以使用类型类,这些类型类是灵活的,并且在编译时解析。

这就是您想要的吗

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 {})
trait MyData
特征粘虫

trait Writer[T您的
MyDataType
看起来像一个
Manifest
,这是Scala的一个附带功能,您应该看看它。MyDataType类似,但实际上它有方法。它是我使用的一个类型类。在我的应用程序中,MyDataType的特定实例实际上是一个类型类。
    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
}
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 {})