web-dev-qa-db-fra.com

Élimination de l'effacement dans scala: l'argument de type non variable n'est pas vérifié car il est éliminé par l'effacement

J'ai une séquence Seq [Any] qui contient une variété d'objets (comme String, Integer, List [String], etc.). J'essaie de parcourir la liste et de la diviser en listes séparées partitionnées en fonction du type de classe. Voici un modèle que j'utilise dans le code:

val allApis = mySequence.filter(_.isInstanceOf[String])

Cela fonctionne bien et ne génère aucun avertissement. Cependant, lorsque j'essaie de faire de même pour filtrer les objets qui sont des listes de chaînes:

val allApis = mySequence.filter(_.isInstanceOf[List[String]])

J'obtiens un avertissement qui dit l'argument de type non variable String dans le type List [String] n'est pas vérifié car il est éliminé par effacement. Maintenant, la technique fonctionne réellement et je suis en mesure de filtrer confortablement la séquence comme vous le souhaitez, mais je me demande quelle est la façon appropriée de gérer l'avertissement de manière idiomatique afin de savoir que je n'ai pas de bug grave tapi dans le fond en attendant de faire exploser

45
BSJ

Cela ne fonctionne pas car il sélectionnera List[Double] ou toute autre liste en plus de List[String]. Il existe plusieurs façons de résoudre le problème, notamment en enveloppant tous les types paramétrés dans une classe de cas non paramétrée:

case class StringList(value: List[String])

et puis vous pouvez juste

mySequence.collect{ case StringList(xs) => xs }

pour extraire les listes de chaînes (avec le type correct et le type en toute sécurité également).

Alternativement, si vous ne voulez pas encapsuler des objets et être sûr qu'ils sont du bon type, vous pouvez vérifier chaque élément:

mySequence.filter( _ match {
  case xs: List[_] => xs.forall( _ match { case _: String => true; case _ => false })
  case _ => false
})

même si cela ne vous permettra pas de savoir de quel type les listes vides étaient censées être.

Une autre possibilité est de coller TypeTags à tout dans votre liste; cela vous évitera d'avoir à envelopper manuellement les choses. Par exemple:

import scala.reflect.runtime.universe.{TypeTag, typeTag}
def add[A](xs: List[(Any, TypeTag[_])], a: A)(implicit tt: TypeTag[A]) = (a, tt) :: xs
val mySequence = add(add(add(Nil, List(42)), true), List("fish"))
mySequence.filter(_._2.tpe weak_<:< typeTag[List[String]].tpe)
69
Rex Kerr
val v = 1 ::"abc" :: true :: Nil
v : List[Any] = List(1,abc,true) 

le paramètre type de type List a été unifié au plus grand super type commun des éléments dans List qui est Any.

Shapeless est à la rescousse.

import shapeless._
import HList._

val s = 1 :: "abc" :: true: HNil
s : shapeless.::[Int,shapeless.::[String,shapelsss.::[Boolean,shapeless.HNil]]]
= 1 :: abc :: true :: HNil

Avec Shapeless HList, vous pouvez obtenir une sécurité de temps de compilation pour une liste hétérogène. vous pouvez désormais filter de manière sécurisée. par exemple.

s.filter[String]
9
Vikas Pandya