Scalaで実行時にクラスパラメータのデータ型を見つける方法
Nov 29 2020
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
か?
私の目的は、実行時にクラスパラメータのデータ型を知り、それを事前定義された型と照合することです。
回答
4 DmytroMitin Nov 29 2020 at 17:20
現在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
れるnullaryメソッドのタイプとタイプだけが異なるタイプであるということです。
追加してみてください .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さんの答え、その目標は、 『パターンマッチング』で、これは(主に)コンパイル時にも行うことができるケースクラスのすべてのフィールドであれば型崩れは:
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
1 TomerShetah Nov 30 2020 at 11:28
@Dmytrioの回答は、リフレクションが期待どおりに機能しなかった理由の優れた説明です。
あなたの質問から、あなたがやろうとしていることは、実際には、ケースクラスにあるすべての変数にパターンマッチしていることがわかります。次の方法で行うことを検討してください。
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")
}
コードはScastieで実行されます。