Scala 从案例类获取字段名和类型(带选项)

Scala 从案例类获取字段名和类型(带选项),scala,generics,reflection,macros,scala-macros,Scala,Generics,Reflection,Macros,Scala Macros,假设我们有一个某物的模型,表示为一个案例类,也是这样 case class User(firstName:String,lastName:String,age:Int,planet:Option[Planet]) sealed abstract class Planet case object Earth extends Planet case object Mars extends Planet case object Venus extends Planet 本质上,通过使用反射或宏,可

假设我们有一个某物的模型,表示为一个
案例类
,也是这样

case class User(firstName:String,lastName:String,age:Int,planet:Option[Planet])

sealed abstract class Planet
case object Earth extends Planet
case object Mars extends Planet
case object Venus extends Planet
本质上,通过使用反射或宏,可以获得用户案例类的字段名以及字段表示的类型。这还包括
选项
,即在提供的示例中,需要能够区分
选项[行星]
和仅
行星

在scala'ish伪代码中,类似这样的代码

val someMap = createTypedMap[User] // Assume createTypedMap is some function which returns map of Strings to Types
someMap.foreach{case(fieldName,someType) {
   val statement = someType match {
       case String => s"$fieldName happened to be a string"
       case Int => s"$fieldName happened to be an integer"
       case Planet => s"$fieldName happened to be a planet"
       case Option[Planet] => s"$fieldName happened to be an optional planet"
       case _ => s"unknown type for $fieldName"

   }
   println(statement)

}
我现在意识到你不能做像
case Option[Planet]
这样的事情,因为它会被Scala的擦除删除,但是即使使用
TypeTags
,我也无法编写完成我要做的事情的代码,也可能无法处理其他类型(比如
或者[SomeError,String]


目前我们正在使用最新版本的Scala(2.11.2),因此任何使用
类型标签
类标签
或宏的解决方案都已经足够了。

选项是一种类型参数化类型(选项[T])。在运行时,除非您已经构建了要使用的代码,否则由于类型擦除(对于所有类型参数化的类型都是如此),您无法区分选项[String]和选项[Int]。 尽管如此,您可以区分选项[*]和行星。记住第一个问题

通过反思,获得类内的所有“东西”是很容易的。例如,假设您只需要getter(您可以放置其他类型的过滤器,它们有很多,并且当继承是过程的一部分时,并非所有的行为都像预期的那样,因此您需要进行一些实验):

如果在实例上而不是在类上调用代码,另一个选项是遍历每个方法,调用该方法并将结果分配给变量,然后测试变量的类型。这假设您只调用不改变实例状态的方法


您有很多选择,有时间为您的需求找到最佳选择。

似乎最好的选择是使用宏(或实现宏的库)。由于所指出的类型擦除问题,试图通过检查getter/setter来检测Option远远不够理想(它也很容易在Scala版本之间中断),Miles Sabin的答案是否有帮助?
import reflect.runtime.{universe=>ru}
val fieldSymbols = ru.typeOf[User].members.collect{ 
    case m: ru.MethodSymbol if m.isGetter => m 
}