Cómo encontrar el tipo de datos del parámetro de clase en tiempo de ejecución en 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")
}
No es capaz de digerir por qué el resultado es en Absurd
lugar de I am int
?
Mi objetivo es conocer el tipo de datos del parámetro de clase en tiempo de ejecución y hacer coincidirlo con tipos predefinidos.
Respuestas
Ambos actuales dataType
y typeOf[Int]
están impresos como, Int
pero si lo hace showRaw
, verá por qué no coinciden
showRaw(dataType) // NullaryMethodType(TypeRef(ThisType(scala), scala.Int, List()))
showRaw(typeOf[Int]) // TypeRef(ThisType(scala), scala.Int, List())
El caso es que solo el tipo Int
y el tipo de método nular que regresa Int
son tipos diferentes.
Intenta agregar .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
También vale la pena mencionar que .decl(TermName("id"))
devuelve el símbolo de obtención, es .decl(TermName("id "))
(con un espacio en blanco) el que devuelve el símbolo de campo. Entonces, alternativamente, puede hacerlo con un espacio en blanco en el nombre del símbolo y sin.resultType
val dataType = getType(thing).decl(TermName("id ")).asTerm.typeSignature
Agregaré a la respuesta de @TomerShetah que si el objetivo es "hacer coincidir el patrón" con todos los campos de una clase de caso, esto también se puede hacer en tiempo de compilación (principalmente) con 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 respuesta de @Dmytrio es una gran explicación de por qué la reflexión no funcionó como esperabas.
Puedo entender por su pregunta, que lo que está tratando de hacer, es que el patrón coincide con todas las variables que tiene en una clase de caso. Considere hacerlo de la siguiente manera:
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")
}
El código se ejecuta en Scastie .