3

我想在运行时以编程方式确定 Scala 类的所有属性。例如,对于以下 Scala 类,我想确定方法name1name3name4name5是 的属性的获取器A

class A(val name1: String, private val name2: String) {
  val name3 = ""
  var name4 = ""
  def name5 = ""
  def name6() = ""
}

大部分工作都可以使用 Java 的反射 API 来完成。不幸的是,我无法检测 和 之间的name5区别name6()。因此,我开始使用 ScalaSigParser 进行下一次试验,但不幸的是,ScalaSig 的name5和标志name6()也是相同的。这是我的代码:

def gettersOf(clazz: Class[_]) = {
  for (ssig <- ScalaSigParser.parse(clazz))
  yield {
    ssig.symbols.toList.collect{
      case m: MethodSymbol => m
    }.filter(m => (m.symbolInfo.flags & 0xFFFFF) == 0x200)
  }
}

gettersOf(classOf[A]).get.foreach{m =>
  println(m.name + ": " + m)
}

正如您在以下输出中看到的那样,两种方法仅在info值上有所不同:

name1: MethodSymbol(name1, owner=0, flags=28400200, info=22 ,None)
<init>: MethodSymbol(<init>, owner=0, flags=200, info=38 ,None)
name3: MethodSymbol(name3, owner=0, flags=8400200, info=45 ,None)
name4: MethodSymbol(name4, owner=0, flags=8000200, info=45 ,None)
name4_$eq: MethodSymbol(name4_$eq, owner=0, flags=8000200, info=54 ,None)
name5: MethodSymbol(name5, owner=0, flags=200, info=45 ,None)
name6: MethodSymbol(name6, owner=0, flags=200, info=66 ,None)

但是,info似乎没有返回静态常量。如果您向该类添加另一个方法,则 的infoname6将发生变化,同时似乎有一些稳定性:

  • name3, name4, 并且name5始终具有相同的info
  • name6并且name5总是有不同的info价值观

有人知道它的含义info以及如何使用它来确定它是哪种方法吗?

相关问题:

4

3 回答 3

8

你最好的选择是使用即将到来的 Scala 2.10 的反射 API。

以下是在 2.10.0-M6 中获取类型属性的方法:

scala> import reflect.runtime.universe._
import reflect.runtime.universe._

scala> typeOf[A].members.view.filter{_.isValue}.filter{!_.isMethod}.toList
res0: List[reflect.runtime.universe.Symbol] = List(variable name4, value name3, value name2, value name1)

不幸的是,还没有太多关于它的阅读材料。不过,关于 SO 有一些已回答的问题。例如,您可能对这个问题感兴趣。另请查看Daniel Sobral 的这篇博文。

于 2012-08-13T13:44:18.333 回答
3
import reflect.runtime.universe._
typeOf[A].members map (m => m -> m.typeSignature) collect { 
  case (m, nm: NullaryMethodType) => m 
}
于 2012-08-13T14:28:06.380 回答
0

我终于找到了解决方案。除了使用原始info值之外,还可以使用更多信息infoType,它似乎NullaryMethodType为所有没有括号的方法返回 a:

def gettersOf(clazz: Class[_]) = {
  for (ssig <- ScalaSigParser.parse(clazz))
  yield {
    ssig.symbols.toList.collect {
      case m: MethodSymbol => m
    }.filter(m => (m.symbolInfo.flags & 0xFFFFF) == 0x200 && m.infoType.isInstanceOf[NullaryMethodType])
  }
}

name6最后,无论有无隐藏<init>方法,我们都得到了想要的结果:

name1: MethodSymbol(name1, owner=0, flags=28400200, info=22 ,None)
name3: MethodSymbol(name3, owner=0, flags=8400200, info=45 ,None)
name4: MethodSymbol(name4, owner=0, flags=8000200, info=45 ,None)
name5: MethodSymbol(name5, owner=0, flags=200, info=45 ,None)
于 2012-08-13T13:16:57.527 回答