引用成员类型的Scala宏
我有一个成员类型的trait,希望有一个签名包含此类型的宏:引用成员类型的Scala宏,scala,scala-macros,scala-2.11,scala-reflect,Scala,Scala Macros,Scala 2.11,Scala Reflect,我有一个成员类型的trait,希望有一个签名包含此类型的宏: trait Foo { class Bar[A] { ... } def baz[A](x: Bar[A]): Bar[A] = macro bazImpl[A] def bazImpl[A: c.WeakTypeTag](c: blackbox.Context)(x: c.Expr[Bar[A]]) = ... } 这不起作用,因为bazImpl必须属于静态(即非成员)对象或宏束。但在这两种情况下,我都没有一个fo
trait Foo {
class Bar[A] { ... }
def baz[A](x: Bar[A]): Bar[A] = macro bazImpl[A]
def bazImpl[A: c.WeakTypeTag](c: blackbox.Context)(x: c.Expr[Bar[A]]) = ...
}
这不起作用,因为bazImpl
必须属于静态(即非成员)对象或宏束。但在这两种情况下,我都没有一个foo:foo
,因此我可以编写foo.Bar[a]
我能想到的一个解决方法是使用Foo#Bar[A]
并添加强制转换:
trait Foo {
class Bar[A] { ... }
def baz[A](x: Bar[A]): Bar[A] = Foo.baz1(x).asInstanceOf[Bar[A]]
def bazImpl[A: c.WeakTypeTag](c: blackbox.Context)(x: c.Expr[Bar[A]]) = ...
}
object Foo {
def baz1[A](x: Foo#Bar[A]): Foo#Bar[A] = macro bazImpl[A]
def bazImpl[A: c.WeakTypeTag](c: blackbox.Context)(x: c.Expr[Foo#Bar[A]]): c.Expr[Foo#Bar[A]] = ...
}
但是我想避免它(既因为它不完全是类型安全的,也因为实际情况更复杂)。有其他选择吗?如果您使用的是Scala 2.11,只需在任何地方编写c.Tree
,而不是c.Expr
。这将减少在宏impl中以几乎零成本指定与宏def中相同类型的样板文件。与EXPR相比,树的唯一潜在缺点是具体化,这要求拼接必须是EXPR,但由于现在Scala中的大多数元程序都是用准IQOOTE编写的,所以这对您来说可能无关紧要。您能在嵌套类中创建嵌套的伴生对象吗?换句话说,创建一个嵌套在Foo
trait中的Bar
对象,该对象包含bazImpl
方法?@BenReich如前所述,宏实现必须在静态对象中。嵌套在Foo
中的对象不是静态的(至少据我所知)。你能解释更多关于Tree和Expr之间的区别,以及Tree如何允许正确的嵌套类,而Expr不允许吗?@EugeneBurmako这可能值得在宏概述中提及(如果不是,至少我没有看到它)。这是对原始问题的回答吗?@BenReich在编写c.Expr时,需要提供一个类型参数来指定基础树的静态类型。此类型必须与宏def的相应参数类型/返回类型对齐,并由编译器验证。编写c.Tree时,它没有类型参数,因此编译器不会验证任何内容。@MilesSabin我认为这个问题没有很好的答案,因此我建议了一种解决潜在问题的解决方法。