在Scala中,获取声明的字段的值被强制转换为类声明的类型

时间:2014-01-13 11:30:46

标签: scala reflection types casting field

我想问一下如何在Scala中实现以下功能。考虑

scala> case class C(i:Int)
defined class C

scala> val c = C(1)
c: C = C(1)

鉴于感兴趣的领域,在这种情况下

scala> val fname = "i"
fname: String = i

我们希望在c中检索字段i的原始值和类型。

第一个天真的尝试包括以下内容,

scala> val f = c.getClass.getDeclaredField(fname)
f: java.lang.reflect.Field = private final int C.i

scala> f.setAccessible(true)

scala> f.getType
res3: Class[_] = int

然而,

scala> val a:Int = f.get(c)
<console>:11: error: type mismatch;
 found   : Object
 required: Int
       val a:Int = f.get(c)
                        ^

换句话说,如何在c(*)

中获取i的Int值
scala> :type -v case class C(i:Int)
// Type signature
AnyRef
        with Product
        with Serializable {
  val i: Int  <----------------------- (*)
  private[this] val i: Int
  def <init>(i: Int): C
  def copy(i: Int): C
...

并且对于不一定是Int类型,请考虑D中的字段j,

scala> case class C(i:Int)
defined class C

scala> case class D(j:C)
defined class D

scala> :type -v case class D(j:C)
// Type signature
AnyRef
        with Product
        with Serializable {
  val j: C
  private[this] val j: C
  def <init>(j: C): D
  def copy(j: C): D
...

非常感谢......

摘要

鉴于

scala> f.get(c)
res1: Object = 1

scala> f.getType
res3: Class[_] = int

如何获得

val a = 1

其中a是Int类型,只知道来自f.getType的类型。

1 个答案:

答案 0 :(得分:2)

f.get(c)静态类型Object,因为它可以是任何类和任何字段。但是,在运行时它将返回IntegerInt的Java包装类)。您可以使用

进行投射
f.get(c).asInstanceOf[Int]

f.getInt(c)

如果您事先知道要求Int字段。如果不这样做,您可以进行模式匹配:

f.get(c) match {
  case i: Integer => ...
  case l: java.lang.Long => ...
  case s: String => ...
  // etc.
}

// actually compiles to same code, but avoids the need to use boxed classes
(f.get(c): Any) match {
  case i: Int => ...
  case l: Long => ...
  case s: String => ...
  // etc.
}

请注意,采用的分支取决于字段的实际值,而不是其类型;例如对于val f: Any = "",将case s: String分支。

或者您可以使用f.getType获取其类型并使您的逻辑依赖于此。