【问题标题】:Scala macros referring to a member type引用成员类型的 Scala 宏
【发布时间】:2015-05-29 20:09:20
【问题描述】:

我有一个成员类型的特征,并且想要一个带有包含此类型的签名的宏:

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 必须属于静态(即非成员)object 或宏包。但在这两种情况下,我都没有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]] = ... 
}

但我想避免它(既因为它不完全是类型安全的,又因为实际情况更复杂)。有其他选择吗?

【问题讨论】:

  • 你能在嵌套类中创建一个嵌套的伴生对象吗?换句话说,让Bar 对象嵌套在包含bazImpl 方法的Foo 特征中?
  • @BenReich 如前所述,宏实现必须在 static 对象中。嵌套在 Foo 中的对象不是静态的(至少据我所知)。

标签: scala scala-macros scala-2.11 scala-reflect


【解决方案1】:

如果您使用的是 Scala 2.11,只需在任何地方写 c.Tree 而不是 c.Expr。这将减少在宏 impls 中指定与在宏 defs 中相同类型的样板,几乎为零成本。与 exprs 相比,树的唯一潜在缺点是 reify,它要求拼接对象是 exprs,但由于现在 Scala 中的大多数元程序都是用准引号编写的,所以这对你来说可能无关紧要。

【讨论】:

  • 您能否详细解释一下 Tree 和 Expr 之间的区别以及 Tree 如何允许正确的嵌套类而 Expr 不允许?
  • @EugeneBurmako 这可能在宏概述中值得一提(如果不是;至少我没见过)。
  • 如何回答原始问题?
  • @BenReich 在编写 c.Expr 时,您需要提供一个类型参数来指定底层树的静态类型。此类型必须与宏 def 的相应参数类型/返回类型对齐,并且由编译器验证。当您编写 c.Tree 时,它​​没有类型参数,因此编译器不会验证任何内容。
  • @MilesSabin 我认为这个问题没有很好的答案,所以我建议了一个解决潜在问题的解决方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-22
  • 1970-01-01
  • 1970-01-01
  • 2021-11-27
  • 2011-01-30
相关资源
最近更新 更多