2010-11-30 25 views
6

Je souhaite créer une hashmap pour stocker les noms de paramètres et leurs valeurs. Les paramètres sont cependant avec des types différents. Je pourrais utiliser HashMap [String, Any], mais je ne saurais pas quels types ils sont plus tard. Y at-il de toute façon je peux récupérer l'information de type? Ou y a-t-il une meilleure façon de stocker la paire?scala reflection

+0

duplicata possible de [Comment contourner l'effacement de type sur Scala? Ou, pourquoi ne puis-je pas obtenir le paramètre type de mes collections?] (Http://stackoverflow.com/questions/1094173/how-do-i-get-around-type-erasure-on-scala-or-why -cant-i-get-the-type-parameter) –

+0

Est-ce que l'une de ces réponses vous a été utile? Si non, avez-vous des commentaires qui nous aideraient à mieux cibler vos besoins? –

+0

Eh bien, aucun d'entre eux n'a vraiment résolu mon problème. On m'a dit (hors ligne) par certaines personnes qu'il n'y a pas de solution élégante. J'ai changé ma conception plus tard pour éviter un tel problème ... – user398384

Répondre

5

Voulez-vous accéder aux informations de type statique ou aux informations de type dynamique? Si vous êtes après le premier, vous pouvez utiliser les touches tapées. Quelque chose le long de ces lignes devrait fonctionner:

final class Key[T] 

object Registry { 
    private var backingMap: Map[Key[_], _] = Map.empty 

    def put[T](k: Key[T], v: T) = backingMap += (k -> v) 

    def get[T](k: Key[T]): Option[T] = backingMap get k map (_.asInstanceOf[T]) 
} 

scala> val strKey = new Key[String] 
strKey: Key[String] = [email protected] 

scala> val intKey = new Key[Int] 
intKey: Key[Int] = [email protected] 

scala> Registry.put(strKey, "asdf") 

scala> Registry.get(strKey) 
res0: Option[String] = Some(asdf) 

scala> Registry.put(intKey, "asdf") 
<console>:10: error: type mismatch; 
found : Key[Int] 
required: Key[Any] 
     Registry.put(intKey, "asdf") 

Alternativement, vous pouvez utiliser les touches typées et stocker les informations de type dans la carte en utilisant les manifestes (comme Daniel suggested):

class Registry[K] { 
    import scala.reflect.Manifest 

    private var _map= Map.empty[K,(Manifest[_], Any)] 

    def put[T](key: K, item: T)(implicit m: Manifest[T]) { 
     _map += (key -> (m, item)) 
    } 

    def get[T](key:K)(implicit m : Manifest[T]): Option[T] = { 
     for ((om, v) <- _map get key if om <:< m) 
     yield v.asInstanceOf[T] 
    } 
} 

Cette dernière approche a l'avantage vous pouvez utiliser n'importe quoi comme une clé, et vous n'avez pas besoin de passer les objets clés typés d'origine. Toutefois, il présente l'inconvénient que vous devez spécifier le type de valeur lorsque vous appelez la méthode get. Si vous spécifiez le mauvais type, vous obtiendrez None comme si la clé ne se trouvait pas du tout dans le Registre, alors qu'avec les clés tapées, vous avez la garantie d'obtenir n'importe quelle valeur associée à une clé.

1

Si vous n'avez pas trop de valeurs, vous pouvez envisager d'utiliser un HList de paires ou de constructions similaires.

3

Voir this, qui implémente exactement ce que vous demandez.

+0

Nice! J'ai légèrement simplifié votre implémentation dans ma réponse et j'ai tenté d'expliquer les différences entre l'approche par clé typée et l'approche du manifeste stocké. –