假设我们要编写一个宏,该宏使用一些类型成员或方法定义一个匿名类,然后使用这些方法创建该类的实例,该实例被静态类型化为结构类型,依此类推。在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
。我知道这可能不是定义的行为,但这有意义吗?有没有一种更干净的方法来从宏获取结构类型(带有方法)?
14
有趣的是,如果您在REPL中编写相同的代码而不是在宏中生成代码,则它可以工作:scala> {final class anon {def x = 2}; new anon} res1:AnyRef {def x:Int} = anon $ 1 @ 5295c398。感谢您的举报!这周我来看一下。
—
Eugene Burmako 2013年
请注意,我在这里提出了一个问题。
—
Travis Brown
不,不是阻止者,谢谢-每当我需要时,额外的匿名类技巧就对我有用。我只是注意到这个问题上有几个反对意见,并对这个状态感到好奇。
—
特拉维斯·布朗
类型成员部分非常容易-> wTF?当然,您非常的裂缝!)
—
ZaoTaoBao13年