2017-09-11 5 views
1

J'ai la valeur mappings:Scala générique générique et type spécifique

val mappings: Map[Class[_] ,Iterable[AttributeKeyAndValue] => AnyRef] 

est-il possible de le rendre plus typé comme

val mappings: Map[Class[T], Iterable[AttributeKeyAndValue] => T] 

T joue le même rôle que underscore. Je pense compilateur de se plaindre, si elle répond à ce code:

val mappings: Map[Class[T], Iterable[AttributeKeyAndValue] => T] = Map(
    classOf[String], attrs => 1) 

Répondre

2

Vous ne pouvez pas paramétrer val s alors non, pas comme ça. En regardant votre demande, cela n'a pas beaucoup de sens. Disons que ceci: val mappings: Map[Class[T], Iterable[AttributeKeyAndValue] => T] était valide et le compilateur se plaindrait.

Vous pouvez soit paramétrer toutes les entrées de la carte avec le même type, c.-à-d. T ou avoir chaque entrée avec son propre type paramétré rendant impossible de savoir quel type il est lors de la récupération des entrées avec les méthodes apply ou get.

Je vous suggère de coller avec le Class[_] car la seule façon de paramétrer ceci est de forcer toutes les entrées à avoir le même type. Par exemple, si vous étiez en mesure de le paramétrer en Map[Class[String], ...], vous ne pourrez mettre qu'une seule entrée dans la carte, celle où la clé est classOf[String]

0

Eh bien, le compilateur ne sait pas ce qui est T dans l'exemple que vous avez fourni. Ainsi, en option, vous pouvez définie mappings fonction paramétrée par T:

 def mappings[T](x: AttributeKeyAndValue => T): 
      Map[Class[T], AttributeKeyAndValue => T] = Map(classOf[T] -> x) 
utilisation

:

val mappping = mappings(x => x.toString) 

et le type compilateur sera en mesure de déduire est:

mappping : Map[Class[String], AttributeKeyAndValue => String] 
+0

Cela fera pour une carte qui ne peut avoir qu'une seule clé. – pedromss

+0

Eh bien, vous avez l'idée.Si vous avez une liste de valeurs que vous devez remplir, vous pouvez passer un seq comme paramètre: 'def mappings [T] (xs: Liste [AttributeKeyAndValue => T]): Map [Classe [T], AttributeKeyAndValue => T] = xs.map (x => classOf [T] -> x) .toMap' – Rumoku

+0

Encore une fois, la carte retournée aura toutes ses clés paramétrées dans le même type. Ce qui serait bien dans les cas normaux, mais ici, si vous mettez un 'classOf [String]' comme une clé dans la carte, vous ne pouvez pas mettre une autre clé comme 'classOf [Int]'. Ceci est juste un comportement non naturel – pedromss

2

Les caractères génériques dans Scala sont simplement un cas simple spécifique de types existentiels, et ce que vous voulez serait un plus complexe parce que vous voulez utiliser le même T à deux endroits. Quelque chose comme Seq[(Class[T], AttributeKeyAndValue => T) forSome { type T }]. Mais notez où vous devez mettre forSome: il n'y a pas d'endroit équivalent si vous voulez Map! Par exemple. Map[Class[T], AttributeKeyAndValue => T] forSome { type T } signifierait qu'il y a un seul T pour l'ensemble de la carte.

Ce que je vous suggère est la création d'un type qui présente une interface plus de sécurité de type, même si vous avez besoin coulés dans:

class Mappings private (contents: Map[Class[_], Iterable[AttributeKeyAndValue] => AnyRef]) { 
    def get[T](clazz: Class[T]) = contents.get(clazz).asInstanceOf[Option[Iterable[AttributeKeyAndValue] => T]] 

    def +[T](clazz: Class[T], value: Iterable[AttributeKeyAndValue] => T) = new Mappings(contents + (clazz, value)) 

    // any other methods you want 
} 

object Mappings { 
    val empty = new Mappings(Map.empty) 
} 

// elsewhere 
Mappings.empty + (classOf[String], attrs => "a") // type-checks 
Mappings.empty + (classOf[String], attrs => 1) // doesn't type-check 

Vous pouvez réellement améliorer l'API pour éviter de passer manuellement les classes, de sorte que vous il suffit d'écrire get[String] et +(attrs => 1) déduit automatiquement il faut classOf[Int], mais j'ai décidé de montrer l'idée simple ici.

+0

Oui, 'mappings 'en fait un val privé dans un tel type de wrapper. –

+0

Dans ce cas, je travaillerais simplement avec 'Map [Class [_], Iterable [AttributeKeyAndValue] => AnyRef]' dans le wrapper. –

0

Envelopper dans une classe de cas?

type Attrs = Iterable[AttributeKeyAndValue] 

    case class Mappings[T](m: Map[Class[T], Attrs => T] 

    object Mappings { 
    implicit def mk[T](m: Map[Class[T], Attrs => T): Mappings[T] = Mappings(m) 
    } 

    val mappings: Mappings[_] = Map(classOf[String] -> { (_:Attrs) => "foo" }) // Works 

    val badMappings: Mappings[_] = Map(classOf[String] -> { (_:Attrs) => 1 }) // Fails