如何在运行时在 Scala 中查找 class 参数数据类型
How to find class parameter datatype at runtime 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")
}
无法理解为什么结果是 Absurd
而不是 I am int
?
我的目标是在运行时了解 class 参数的数据类型并将其与预定义类型相匹配。
当前的 dataType
和 typeOf[Int]
都打印为 Int
但如果你这样做 showRaw
你就会明白为什么它们不匹配
showRaw(dataType) // NullaryMethodType(TypeRef(ThisType(scala), scala.Int, List()))
showRaw(typeOf[Int]) // TypeRef(ThisType(scala), scala.Int, List())
问题是类型 Int
和 nullary 方法返回的类型 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"))
returns getter 符号,returns 字段是 .decl(TermName("id "))
(有空格 space)象征。因此,您也可以在符号名称中使用空白 space 而没有 .resultType
val dataType = getType(thing).decl(TermName("id ")).asTerm.typeSignature
我会添加到 @TomerShetah 的 that if the goal is "pattern matching" all fields of a case class then this can be done also at compile time (mostly) with 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
@Dmytrio 的回答很好地解释了为什么反射没有按您预期的那样工作。
我可以从你的问题中了解到,你试图做的实际上是模式匹配你在一个案例 class 中拥有的所有变量。请考虑按以下方式进行:
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。
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
?
我的目标是在运行时了解 class 参数的数据类型并将其与预定义类型相匹配。
当前的 dataType
和 typeOf[Int]
都打印为 Int
但如果你这样做 showRaw
你就会明白为什么它们不匹配
showRaw(dataType) // NullaryMethodType(TypeRef(ThisType(scala), scala.Int, List()))
showRaw(typeOf[Int]) // TypeRef(ThisType(scala), scala.Int, List())
问题是类型 Int
和 nullary 方法返回的类型 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"))
returns getter 符号,returns 字段是 .decl(TermName("id "))
(有空格 space)象征。因此,您也可以在符号名称中使用空白 space 而没有 .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
@Dmytrio 的回答很好地解释了为什么反射没有按您预期的那样工作。
我可以从你的问题中了解到,你试图做的实际上是模式匹配你在一个案例 class 中拥有的所有变量。请考虑按以下方式进行:
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。