7

マクロを使用してパッケージの下の各クラスのListを返す方法はありますか?TypeSymbol

私が達成しようとしているのは、このリストと同等のものを与えるマクロを書くことです:

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 の下にある extends の下のクラスのすべての型シンボルを取得するマクロは次の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

2番目のものは次のように出力されます:

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 を使用。

前もって感謝します!

4

1 に答える 1

7

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$

またはマクロ自体で。

于 2013-07-15T12:59:11.360 に答える