2011-07-06 4 views
1

Je suis en train de faire quelque chose à peu près comme suit:types existentialistes et la correspondance de Scala

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 
} 

Je voudrais changer cela à quelque chose comme

data.foreach { 
    case (type: MyDataType[T], map: Map[T#MyIdType, T]) forSome { 
    type T <: MyData } => 
    // do save logic 
    // COMPILER COMPLAINS - not found: type T 
} 

mais il n » On dirait que je peux utiliser des types existentiels dans des déclarations de cas. Notez que je ne me soucie pas de la sécurité des types manquants à ce stade parce que mes données sont déjà groupées par type, donc je veux juste un moyen de forcer le compilateur à accepter un type I à travers. Aucune suggestion? J'ai essayé aussi une déclaration de paramétrez cas, mais qui était un no go:

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 
} 

Toute idée de la façon de faire ce que je veux?

+0

Votre 'MyDataType' ressemble à un' Manifest', une fonctionnalité incluse de Scala que vous devriez jeter un oeil à. – shellholic

+0

MyDataType est similaire, même si en réalité il a des méthodes. C'est une classe de type que j'utilise. –

Répondre

0

Je suis tenté de dire que même s'il y a une solution à votre question, il y a quelque chose qui ne sonne pas bien dans votre conception. D'une part, vous utilisez des types complexes qui sont bons pour la sécurité de type et l'inférence à l'heure de compilation. D'autre part, vous utilisez une carte pour stocker runtime informations. Donc non plus, vous simplifiez vos traits et oubliez la sécurité de type, ou vous oubliez de stocker des types dans les cartes à l'exécution. Par exemple, si vous souhaitez associer un rédacteur à une sous-classe MyData particulière, vous pouvez utiliser des classes de type, flexibles et résolues au moment de la compilation.

+0

Dans mon application, l'instance particulière de MyDataType est en fait une classe de type. –

0

Est-ce que c'est ce que vous voulez?

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. vous voulez sûrement une meilleure logique de recherche ici
Questions connexes