Как найти тип данных параметра класса во время выполнения в 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")
}
Не в состоянии переварить, почему Absurdвместо I am int?
Моя цель - узнать тип данных параметра класса во время выполнения и сопоставить его с предопределенными типами.
Ответы
Оба текущих dataTypeи typeOf[Int]напечатаны так, Intно если вы это сделаете, showRawвы увидите, почему они не совпадают
showRaw(dataType) // NullaryMethodType(TypeRef(ThisType(scala), scala.Int, List()))
showRaw(typeOf[Int]) // TypeRef(ThisType(scala), scala.Int, List())
Дело в том, что просто тип Intи тип возвращаемого нулевого метода Int- разные типы.
Попробуй добавить .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
Также стоит упомянуть, что .decl(TermName("id"))возвращает символ получения, он .decl(TermName("id "))(с пробелом) возвращает символ поля. В качестве альтернативы вы можете использовать пробел в имени символа и без.resultType
val dataType = getType(thing).decl(TermName("id ")).asTerm.typeSignature
Я добавлю к @TomerShetah «s ответ , что если цель„ по шаблону“все поля в случае класса , то это может быть сделано также во время компиляции ( в основном) с бесформенными :
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
Ответ @Dmytrio - отличное объяснение, почему отражение не сработало так, как вы ожидали.
Из вашего вопроса я понимаю, что то, что вы пытаетесь сделать, на самом деле соответствует шаблону для всех переменных, которые у вас есть в классе case. Пожалуйста, подумайте о том, чтобы сделать это следующим образом:
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")
}
Выполните код на Скэсти .