从macros中获取具有匿名类方法的结构types

假设我们要编写一个macros来定义一个具有某种types成员或方法的匿名类,然后创build一个静态types为该类方法的类的实例,等等。2.10中的这个macros系统是可能的。 0,types成员部分非常简单:

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方法的便利特征 。)

这个macros允许我们将匿名类的types成员的名字指定为一个string:

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

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

 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) )) } 

但是,当我们尝试一下,我们不会得到一个结构types:

 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 

这非常方便 – 它可以让你做这样的事情,例如 – 但我不明白为什么它的作品,和types成员版本的作品,但不是bar 。 我知道这可能不是定义的行为 ,但它有什么意义? 有没有更macros观的方法来获得结构types(与方法)?

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

我们的英雄在着名的“Skylla和Charybdis”部分确定了什么应该逃避黑暗的匿名,并将光看作是结构types的一员。

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

如果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) } } 
Interesting Posts