So finden Sie den Datentyp für Klassenparameter zur Laufzeit in 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")
}
Nicht in der Lage zu verdauen, warum Ergebnis Absurd
statt ist I am int
?
Mein Ziel ist es, den Datentyp des Klassenparameters zur Laufzeit zu kennen und ihn mit vordefinierten Typen abzugleichen.
Antworten
Beide sind aktuell dataType
und typeOf[Int]
werden so gedruckt, Int
aber wenn Sie dies tun, werden showRaw
Sie sehen, warum sie nicht übereinstimmen
showRaw(dataType) // NullaryMethodType(TypeRef(ThisType(scala), scala.Int, List()))
showRaw(typeOf[Int]) // TypeRef(ThisType(scala), scala.Int, List())
Die Sache ist, dass nur der Typ Int
und der Typ der zurückgegebenen Nullmethode Int
unterschiedliche Typen sind.
Versuchen Sie hinzuzufügen .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
Erwähnenswert ist auch, dass .decl(TermName("id"))
das Getter-Symbol .decl(TermName("id "))
(mit einem Leerzeichen) das Feldsymbol zurückgibt. Alternativ können Sie also mit und ohne Leerzeichen im Symbolnamen arbeiten.resultType
val dataType = getType(thing).decl(TermName("id ")).asTerm.typeSignature
Ich werde hinzufügen @TomerShetah ‚s Antwort , dass , wenn das Ziel‚Pattern Matching‘ werden alle Felder einer Fallklasse ist , dann kann dies auch (meistens) bei der Kompilierung durchgeführt werden mit 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
Die Antwort von @Dmytrio ist eine großartige Erklärung dafür, warum die Reflexion nicht wie erwartet funktioniert hat.
Ich kann anhand Ihrer Frage verstehen, dass Sie tatsächlich versuchen, alle Variablen, die Sie in einer Fallklasse haben, mit Mustern abzugleichen. Bitte denken Sie daran, dies folgendermaßen zu tun:
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 läuft bei Scastie .