2

我有两个案例类定义如下

object Outer {
   case class OuterCase(outerParam: Int)
   object Inner {
      case class InnerCase(innerParam: Int)
   }
}

我想像这样获取他们实例的字段名称:

import scala.tools.nsc.interpreter.ProductCompletion

object EncapsulatedCase extends App {
   val outer = Outer.OuterCase(1)
   println("outer: " + new ProductCompletion(outer).caseNames)

   val inner = Outer.Inner.InnerCase(2)
   println("inner: " + new ProductCompletion(inner).caseNames)
}

这对对象按预期工作outer,但对inner. 这是输出:

outer: List(outerParam)
inner: List()

我看到的唯一区别是类InnerCase是在一个对象中定义的,它本身在另一个对象中定义,而OuterCase只包含在一个对象中。

为什么会有问题?为什么我可以得到 case 对象的参数名称outer而不是innercase 对象?

我在 Scala 2.9.2 中观察到了这种行为。

谢谢!

一些附加说明

我注意到使用scala或使用 sbt 从命令行运行相同的编译类是不同的。

从命令行:

julien@minare:~/prog/testing$ scala -version
Scala code runner version 2.9.2 -- Copyright 2002-2011, LAMP/EPFL
julien@minare:~/prog/testing$ scala -cp target/scala-2.9.2/classes:/Users/julien/.sbt/boot/scala-2.9.2/lib/scala-library.jar:/Users/julien/.ivy2/cache/org.scala-lang/scalap/jars/scalap-2.9.2.jar:
/Users/julien/.sbt/boot/scala-2.9.2/lib/scala-compiler.jar org.example.EncapsulatedCase
outer: List(outerParam)
inner: List()

但是使用 sbt:

> scala-version
[info] 2.9.2
> sbt-version
[info] 0.11.2
> show external-dependency-classpath
[info] ArrayBuffer(Attributed(/Users/julien/.sbt/boot/scala-2.9.2/lib/scala-library.jar), Attributed(/Users/julien/.ivy2/cache/org.scala-lang/scalap/jars/scalap-2.9.2.jar), Attributed(/Users/julien/.sbt/boot/scala-2.9.2/lib/scala-compiler.jar))
[success] Total time: 0 s, completed Apr 24, 2012 9:20:21 AM
> run-main org.example.EncapsulatedCase
[info] Running org.example.EncapsulatedCase 
outer: List()
inner: List()

任何有关找出这里发生的事情的提示将不胜感激。

4

1 回答 1

1

我没有找到对正在发生的事情的解释,但我找到了一种使用 Java 反射的方法。

因此,我仍然非常感谢解决ProductCompletion行为的答案。

这是对在主构造函数中声明的类字段的尝试。这不是什么新鲜事,也不能保证有效。我将在下面简要解释原因。

def caseNameTypeValues(a: AnyRef) = caseFields(a).map{field => (field.getName, field.getType, field.get(a))}
def caseFields(a: AnyRef) = a.getClass.getDeclaredFields.toSeq.filterNot(_.isSynthetic).take(numConstructorParams(a)).map{field =>
        field.setAccessible(true)
        field
}
def numConstructorParams(a: AnyRef) = a.getClass.getConstructors()(0).getParameterTypes.size

numConstructorParams(AnyRef)给出由 返回的第N一个构造函数的参数数量getConstructors(),并caseFields(AnyRef)返回由 返回的第一个N字段getDeclaredFields()caseNameTypeValues(AnyRef)将这些字段映射到它们的名称、类型和值。

警告:这不能保证有效,因为根据Java APIgetConstructors()getDeclaredFields()方法返回的数组“没有排序,也没有任何特定的顺序” 。

如果幸运的话,这会给出预期的结果:

object Outer {
   case class OuterCase(outerParam: Int)
   object Inner {
      case class InnerCase(innerParam: Int)
   }
} 

println(caseNameTypeValues(Outer.OuterCase(1)))
println(caseNameTypeValues(Outer.Inner.InnerCase(2)))

输出

ArrayBuffer((outerParam,int,1))
ArrayBuffer((innerParam,int,2))
于 2012-04-25T12:45:11.700 回答