从宏中获取具有匿名类方法的结构类型

假设我们要编写一个宏来定义一个带有某些类型成员或方法的匿名类,然后创建一个静态类型为该类方法的结构类型的类的实例,等等。这对于2.10中的宏系统是可能的。 0,并且类型成员部分非常容易:

object MacroExample extends ReflectionUtils {
  import scala.language.experimental.macros
  import scala.reflect.macros.Context

  def foo(name: String): Any = macro foo_impl
  def foo_impl(c: Context)(name: c.Expr[String]) = {
    import c.universe._

    val Literal(Constant(lit: String)) = name.tree
    val anon = newTypeName(c.fresh)

    c.Expr(Block(
      ClassDef(
        Modifiers(Flag.FINAL), anon, Nil, Template(
          Nil, emptyValDef, List(
            constructor(c.universe),
            TypeDef(Modifiers(), newTypeName(lit), Nil, TypeTree(typeOf[Int]))
          )
        )
      ),
      Apply(Select(New(Ident(anon)), nme.CONSTRUCTOR), Nil)
    ))
  }
}

(其中ReflectionUtils是一种提供我的constructor方法的便利特性。)

这个宏允许我们将匿名类的类型成员的名称指定为字符串文字:

scala> MacroExample.foo("T")
res0: AnyRef{type T = Int} = $1$$1@7da533f6

请注意,它是适当类型的。 我们可以确认一切都按预期工作:

scala> implicitly[res0.T =:= Int]
res1: =:=[res0.T,Int] = <function1>

现在假设我们试图用一种方法做同样的事情:

def bar(name: String): Any = macro bar_impl
def bar_impl(c: Context)(name: c.Expr[String]) = {
  import c.universe._

  val Literal(Constant(lit: String)) = name.tree
  val anon = newTypeName(c.fresh)

  c.Expr(Block(
    ClassDef(
      Modifiers(Flag.FINAL), anon, Nil, Template(
        Nil, emptyValDef, List(
          constructor(c.universe),
          DefDef(
            Modifiers(), newTermName(lit), Nil, Nil, TypeTree(),
            c.literal(42).tree
          )
        )
      )
    ),
    Apply(Select(New(Ident(anon)), nme.CONSTRUCTOR), Nil)
  ))
}

但是当我们尝试一下时,我们没有得到结构类型:

scala> MacroExample.bar("test")
res1: AnyRef = $1$$1@da12492

但是如果我们在那里附加一个额外的匿名课程:

def baz(name: String): Any = macro baz_impl
def baz_impl(c: Context)(name: c.Expr[String]) = {
  import c.universe._

  val Literal(Constant(lit: String)) = name.tree
  val anon = newTypeName(c.fresh)
  val wrapper = newTypeName(c.fresh)

  c.Expr(Block(
    ClassDef(
      Modifiers(), anon, Nil, Template(
        Nil, emptyValDef, List(
          constructor(c.universe),
          DefDef(
            Modifiers(), newTermName(lit), Nil, Nil, TypeTree(),
            c.literal(42).tree
          )
        )
      )
    ),
    ClassDef(
      Modifiers(Flag.FINAL), wrapper, Nil,
      Template(Ident(anon) :: Nil, emptyValDef, constructor(c.universe) :: Nil)
    ),
    Apply(Select(New(Ident(wrapper)), nme.CONSTRUCTOR), Nil)
  ))
}

有用:

scala> MacroExample.baz("test")
res0: AnyRef{def test: Int} = $2$$1@6663f834

scala> res0.test
res1: Int = 42

这非常方便 - 它可以让你做这样的事情,例如 - 但我不明白它为什么会起作用,并且类型成员版本起作用,但不是bar 。 我知道这可能不是定义的行为,但它有任何意义吗? 是否有更简洁的方法从宏中获取结构类型(以及其中的方法)?


这个问题在这里由Travis一式两份回答。 在跟踪器和Eugene的讨论中(在评论和邮件列表中)有问题的链接。

我们的英雄在着名的“Skylla和Charybdis”部分的类型检查器中决定什么应该逃避黑暗的匿名,并将光看作是结构类型的一员。

有几种方法可以欺骗类型检查器(这不需要奥德赛斯抱抱羊的策略)。 最简单的方法是插入一个伪语句,以使块看起来不像是一个匿名类,然后是它的实例。

如果typer注意到你是一个外部没有引用的公共术语,它会让你变得私人。

object Mac {
  import scala.language.experimental.macros
  import scala.reflect.macros.Context

  /* Make an instance of a structural type with the named member. */
  def bar(name: String): Any = macro bar_impl

  def bar_impl(c: Context)(name: c.Expr[String]) = {
    import c.universe._
    val anon = TypeName(c.freshName)
    // next week, val q"${s: String}" = name.tree
    val Literal(Constant(s: String)) = name.tree
    val A    = TermName(s)
    val dmmy = TermName(c.freshName)
    val tree = q"""
      class $anon {
        def $A(i: Int): Int = 2 * i
      }
      val $dmmy = 0
      new $anon
    """
      // other ploys
      //(new $anon).asInstanceOf[{ def $A(i: Int): Int }]
      // reference the member
      //val res = new $anon
      //val $dmmy = res.$A _
      //res
      // the canonical ploy
      //new $anon { }  // braces required
    c.Expr(tree)
  }
}
链接地址: http://www.djcxy.com/p/86199.html

上一篇: Getting a structural type with an anonymous class's methods from a macro

下一篇: Scala: Overwriting a Generic Java Method that returns null