Comment trouver le type de données de paramètre de classe au moment de l'exécution dans scala
import scala.reflect.runtime.universe
import scala.reflect.runtime.universe._
def getType[T: TypeTag](obj: T) = typeOf[T]
case class Thing(
val id: Int,
var name: String
)
val thing = Thing(1, "Apple")
val dataType = getType(thing).decl(TermName("id")).asTerm.typeSignature
dataType match {
case t if t =:= typeOf[Int] => println("I am Int")
case t if t =:= typeOf[String] => println("String, Do some stuff")
case _ => println("Absurd")
}
Incapable de comprendre pourquoi le résultat est Absurd
au lieu de I am int
?
Mon objectif est de connaître le type de données du paramètre de classe au moment de l'exécution et de le faire correspondre à des types prédéfinis.
Réponses
Les deux sont à jour dataType
et typeOf[Int]
sont imprimés comme Int
mais si vous le faites, showRaw
vous verrez pourquoi ils ne correspondent pas
showRaw(dataType) // NullaryMethodType(TypeRef(ThisType(scala), scala.Int, List()))
showRaw(typeOf[Int]) // TypeRef(ThisType(scala), scala.Int, List())
Le fait est que seuls le type Int
et le type de méthode nullaire retournant Int
sont des types différents.
Essayez d'ajouter .resultType
val dataType = getType(thing).decl(TermName("id")).asTerm.typeSignature.resultType
dataType match {
case t if t =:= typeOf[Int] => println("I am Int")
case t if t =:= typeOf[String] => println("String, Do some stuff")
case _ => println("Absurd")
} // I am Int
Il convient également de mentionner que .decl(TermName("id"))
renvoie le symbole getter, c'est .decl(TermName("id "))
(avec un espace vide) qui renvoie le symbole de champ. Donc, vous pouvez également le faire avec un espace vide dans le nom du symbole et sans.resultType
val dataType = getType(thing).decl(TermName("id ")).asTerm.typeSignature
Je vais ajouter à @TomerShetah de réponse que si l'objectif est tous les champs d'une classe de cas « pattern matching » , alors cela peut être fait aussi au moment de la compilation ( la plupart du temps) avec Shapeless :
import shapeless.Poly1
import shapeless.syntax.std.product._
object printTypes extends Poly1 {
implicit val int: Case.Aux[Int, Unit] = at(t => println(s"I am Int: $t")) implicit val string: Case.Aux[String, Unit] = at(t => println(s"String, Do some stuff: $t"))
implicit def default[V]: Case.Aux[V, Unit] = at(t => println(s"Absurd: $t"))
}
thing.toHList.map(printTypes)
// I am Int: 1
// String, Do some stuff: Apple
https://scastie.scala-lang.org/DmytroMitin/N4Idk4KcRumQJZE2CHC0yQ
La réponse @Dmytrio est une excellente explication pour laquelle la réflexion n'a pas fonctionné comme prévu.
D'après votre question, je peux comprendre que ce que vous essayez de faire, c'est en fait une correspondance de modèle avec toutes les variables que vous avez dans une classe de cas. Veuillez envisager de le faire de la manière suivante:
case class Thing(id: Int, name: String)
val thing = Thing(1, "Apple")
thing.productIterator.foreach {
case t: Int => println(s"I am Int: $t") case t: String => println(s"String, Do some stuff: $t")
case t => println(s"Absurd: $t")
}
Code exécuté chez Scastie .