【问题标题】:Scala Macros: Getting a List of TypeSymbols to be used at runtimeScala 宏:获取要在运行时使用的类型符号列表
【发布时间】:2013-07-15 11:42:41
【问题描述】:

有没有办法使用宏为包下的每个类返回ListTypeSymbols?

我想要实现的是编写一个宏来给出与这个列表等效的东西:

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

scala> case class MyClass1()
defined class MyClass1

scala> case class MyClass2()
defined class MyClass2

scala> val typeSymbols = List(typeOf[MyClass1].typeSymbol, typeOf[MyClass2].typeSymbol)
typeSymbols: List[reflect.runtime.universe.Symbol] = List(class MyClass1, class MyClass2)

这是我的设置:

我有一个名为foo 的包,在其下定义了这些:

trait FooTrait

case class Bar() extends FooTrait 

case class Bar() extends FooTrait

这是我的宏,它获取 foo 下扩展 FooTrait 的类的所有类型符号:

def allTypeSymbols_impl[T: c.WeakTypeTag](c: Context)(packageName: c.Expr[String]) = {
  import c.universe._

  // Get package name from the expression tree
  val Literal(Constant(name: String)) = packageName.tree

  // Get all classes under given package name
  val pkg = c.mirror.staticPackage(name)

  // Obtain type symbols for the classes - implementation omitted
  val types = getTypeSymbols(c.universe)(List(pkg))

  // Apply method for List. For easy readability in later applications
  val listApply = Select(reify(List).tree, newTermName("apply"))

  val result = types.map {
    t =>
      val typeName = c.Expr[TypeSymbol](Ident(t))
      println(s"Typename: $typeName, $t, ${t.toType}")

      reify(typeName.splice).tree
  }

  println(s"RESULT: ${showRaw(result)}")

  c.Expr[List[reflect.runtime.universe.TypeSymbol]](Apply(listApply, result.toList))
}

第一个println 打印:

Typename: Expr[c.universe.TypeSymbol](Bar), class Bar, foo.Bar
Typename: Expr[c.universe.TypeSymbol](Baz), class Baz, foo.Baz

第二个打印:

RESULT: List(Ident(foo.Bar), Ident(foo.Baz))

但我收到此错误消息:

[error] no type parameters for method any2ArrowAssoc: (x: A)ArrowAssoc[A] exist so that it can be applied to arguments (<notype>)
[error]  --- because ---
[error] argument expression's type is not compatible with formal parameter type;
[error]  found   : <notype>
[error]  required: ?A
[error] Note that <none> extends Any, not AnyRef.
[error] Such types can participate in value classes, but instances
[error] cannot appear in singleton types or in reference comparisons.

我应该怎么做才能完成这项工作?我怀疑我必须写别的东西而不是Ident,但我不知道是什么。

使用 Scala 2.10.2。

提前致谢!

【问题讨论】:

    标签: scala macros scala-macros


    【解决方案1】:

    您必须使用reifyType 在运行时世界中创建反射工件:

    import scala.language.experimental.macros
    import scala.reflect.macros.Context
    
    object PackageMacros {
      def allTypeSymbols[T](packageName: String) = macro allTypeSymbols_impl[T]
    
      def allTypeSymbols_impl[T: c.WeakTypeTag](c: Context)(
        packageName: c.Expr[String]
      ) = {
        import c.universe._
    
        val pkg = packageName.tree match {
          case Literal(Constant(name: String)) => c.mirror.staticPackage(name)
        }
    
        val types = pkg.typeSignature.members.collect {
          case sym: ClassSymbol =>
            c.reifyType(treeBuild.mkRuntimeUniverseRef, EmptyTree, sym.toType)
        }.toList
    
        val listApply = Select(reify(List).tree, newTermName("apply"))
    
        c.Expr[List[Any]](Apply(listApply, types))
      }
    }
    

    这将为您提供类型标签列表,而不是符号,但您可以很容易地获得符号,如下所示:

    scala> PackageMacros.allTypeSymbols("foo").map(_.tpe.typeSymbol) foreach println
    class Baz$
    class Bar
    class Baz
    trait FooTrait
    class Bar$
    

    或者在宏本身中。

    【讨论】:

    • 再次感谢特拉维斯!我在宏中将它们转换为TypeSymbols。我在案例类中声明的val 字段中使用符号创建了Map,但在尝试访问它时出现此错误:pastebin.com/8dHDRMYy 我是否应该放宽类型要求并选择Any像你一样?另外,我将如何为 MethodSymbols 执行此操作?有办法吗?
    猜你喜欢
    • 2010-09-16
    • 1970-01-01
    • 2021-02-04
    • 1970-01-01
    • 2018-08-12
    • 1970-01-01
    • 1970-01-01
    • 2018-04-21
    • 1970-01-01
    相关资源
    最近更新 更多