获取字段名称和类型从案例类(含选项)

问题描述:

假设我们的东西的模型,表示为case class,因为这样获取字段名称和类型从案例类(含选项)

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 

本质上,或者通过使用反射,或宏的,要能够获取用户案例类的字段名称以及字段表示的类型。这也包括Option,即在所提供的例子,需要能够在Option[Planet],只是一个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时,我也无法编写代码来完成我正在尝试做的事情,并可能处理其他类型(如Either[SomeError,String])。

目前我们使用的是最新版本的Scala(2.11.2),所以任何使用TypeTagsClassTags或宏的解决方案都会绰绰有余。

+0

英里萨宾的答案http://*.com/questions/23192760/safely-copying-fields-between-case-classes-of-different-types有帮助吗? – 2014-12-28 04:54:46

这是一个远射,但也许Shapeless可以帮助你。

+0

有没有什么特殊的Shapeless,你可以指向哪些可以让你做到这一点? – mdedetrich 2014-10-27 23:34:06

+0

无形有将元组转换为HList的方法,期望将案例类转换为HList是合理的。 HLists是完全键入的,所以你可以对它们进行匹配。但正如我写的,它是一个远射:) – 2014-10-28 10:55:49

+0

RúnarÓli的另一个提示(不知道这是如何工作的):使用模式匹配器将字符串解析为Scala宏中的类型。 '(s:String)=> {val q“type T = $ t”= c.parse(s“type T = $ s”); t}' – 2014-10-28 10:58:50

选项是一个类型参数化类型(选项[T])。在运行时,除非已经将代码构造为使用type tags,否则由于类型擦除(对于所有类型参数化类型都是如此),您无意区分Option [String]和Option [Int]。尽管如此,您可以区分Option [*]和Planet。请记住第一个问题。

通过反思,让一个班级内的所有“事物”变得容易。例如,假设你只需要获取者(你可以放置其他类型的过滤器,其中有很多过滤器,并且当继承是过程的一部分时,并不是所有的行为都如预期的那样,所以你需要尝试一下):

import reflect.runtime.{universe=>ru} 
val fieldSymbols = ru.typeOf[User].members.collect{ 
    case m: ru.MethodSymbol if m.isGetter => m 
} 

你有,如果你正在呼吁实例,而不是类的代码另一种选择,是要经过每一个方法,调用方法和结果分配给一个变量,然后测试类型的变量。这假定你只调用不改变实例状态的方法。

您有很多选择,有时间为您找到最适合您需要的选项。

+0

看起来最好的选择是使用宏或者某个实现了宏的库) 由于正在指出的类型擦除问题,试图通过检查getters/setters来检测Option是非常不理想的(它也可以轻松地在Scala发布) – mdedetrich 2014-10-27 23:39:51