Экзистенциальные типы и сопоставление с образцом в Scala - PullRequest
1 голос
/ 06 июля 2011

Я пытаюсь сделать что-то вроде следующего:

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.Обратите внимание, что в данный момент меня не интересует отсутствие безопасности типов, потому что мои данные уже сгруппированы по типам, поэтому я просто хочу, чтобы компилятор принял тип, через который я проходил.Какие-либо предложения?Я также пытался параметризовать оператор case, но это было бесполезно:

    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 голосов
/ 07 июля 2011

Это то, что вы хотите?

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. вам наверняка нужна более совершенная логика поиска
0 голосов
/ 07 июля 2011

Я испытываю соблазн сказать, что даже если есть решение вашего вопроса, есть что-то, что не звучит прямо в вашем дизайне.С одной стороны, вы используете сложные типы, которые хороши для безопасности типов и логического вывода на время компиляции .С другой стороны, вы используете карту для хранения времени выполнения информации.Так что либо вы упростите свои черты и забудете о безопасности типов, либо забудете о хранении типов в картах во время выполнения.

Например, если вы хотите связать средство записи с определенным подклассом MyData, вы можете использоватьклассы типов, которые являются гибкими и разрешаются во время компиляции.

...