从版本2.11开始,scalareflectionfunction(特别是wrt注释)的(当前)状态是什么?

scala似乎是JVM世界的一个很好的补充。 它让我想起了嵌套在JVM世界中的C ++,C#和Swift的奇怪混合体。

但是,由于缺少或过时的文档,许多scala的function可能无法访问。

就其reflection能力而言,这似乎尤其如此。

例如,我正在评估是否可以使用scala注释在运行时或编译时扩充scala类。 我使用的是最新的scala版本2.11。 作为一个激励性的例子,让我说我创建一个case class SimpleAnnotation() extends StaticAnnotation 。 我想在运行时找到带有该注释的所有case class

这可能是注释最典型和最简单的用例。

在C#和Java中,在运行时确定给定的类是否被注释是相对简单的。 这是一个规范的用例,带有规范的答案。 然而,在scala中,我不清楚我应该做些什么来实现这种行为,甚至是否可能。 特别是,在scala注释和reflection上扫描一些以前的材料后,我想知道:

  • 这可能吗?
  • 这只能在运行时或complile时间吗?
  • 这只能在scala版本2.10之前或之后实现吗?
  • 这只能在scala类上使用Java注释吗?
  • 为什么getClass[AnnotatedClass].getAnnotations返回如此看似乱码的信息?
  • 为什么宏和reflection似乎在scala中混淆了?

任何指导都表示赞赏……我确信我不是唯一一个感到困惑的人。

Reflection和Mac分享了很多API,因为它们基本上是一样的:元编程。 您可以生成并执行代码,您必须反映类型等。 当然存在一些差异:在编译时您无法反映运行时实例,并且在运行时您无法访问编译期间删除的方法,范围和其他信息的内部结构。

这两个API仍然是实验性的,将来可能会在某些部分发生变化,但它们非常实用且记录完备。 Scala是一种多function语言,它们比Java中的API复杂得多。

本文档为您带来了很多:

http://www.scala-lang.org/api/2.11.7/scala-reflect/

http://www.scala-lang.org/api/2.11.7/scala-compiler/

http://docs.scala-lang.org/overviews/ (页面底部)

getClass[AnnotatedClass].getAnnotations您提供Java注释,以获取Scala注释,您必须获取Scala类型而不是仅获取类。

可以在运行时以及编译期间访问reflection,但是有三种注释:

  1. 仅在代码中的纯注释:这些可以从编译单元中的宏访问,其中宏被调用,其中宏可以访问AST

  2. 通过编译单元共享的StaticAnnotations:可以通过scala reflection api访问这些注释

  3. ClassfileAnnotations:这些表示存储为java注释的注释。 如果要通过Java Reflection API访问它们,则必须使用Java定义它们。

这是一个例子:

 @SerialVersionUID(1) class Blub 

现在,我们可以通过这种方式获得注释:

 import scala.reflect.runtime.universe._ val a = typeOf[Blub].typeSymbol.annotations.head 

我们实际得到的不是注释的实例。 运行时环境只是为我们提供了在字节代码中编写的内容:生成注释的scala代码。 你可以打印出你得到的AST:

 showRaw(a.tree) 

现在,这已经是一个相当复杂的结构,但我们可以使用模式匹配来分解它:

 val Apply(_, List(AssignOrNamedArg(_,Literal(Constant(value))))) = a.tree val uid = value.asInstanceOf[Long] 

这对于非常简单的注释是可以的(但我们可以用Java编写它们并依赖于JVM为我们创建实例)。 如果我们真的想要评估该代码并生成注释类的实例,该怎么办? (对于@SerialVersionUID,这对我们没有多大帮助,因为该类实际上不提供对id的访问权限…)我们也可以这样做:

 case class MyAnnotation(name: String) extends annotation.ClassfileAnnotation @MyAnnotation(name = "asd") class MyClass object MyApp extends App { import reflect.runtime.universe._ import scala.reflect.runtime.currentMirror import scala.tools.reflect.ToolBox val toolbox = currentMirror.mkToolBox() val annotation = typeOf[MyClass].typeSymbol.annotations.head val instance = toolbox.eval(toolbox.untypecheck(annotation.tree)) .asInstanceOf[MyAnnotation] println(instance.name) } 

请注意,这将调用编译器,这需要一些时间,特别是如果您是第一次这样做。 复杂的元编程应该在Scala的编译时完成。 Java中的许多东西只在运行时完成,因为你只能运行时元编程(嗯,有注释处理器,但它们更有限)。