Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
引用成员类型的Scala宏_Scala_Scala Macros_Scala 2.11_Scala Reflect - Fatal编程技术网

引用成员类型的Scala宏

引用成员类型的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,希望有一个签名包含此类型的宏:

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我认为这个问题没有很好的答案,因此我建议了一种解决潜在问题的解决方法。