是否可以集成Cake-Pattern和Macros?

jes*_*slg 5 macros scala self-type cake-pattern scala-2.10

我必须在一个使用蛋糕模式的项目中集成一些宏.这种模式使我们能够避免数以万计的进口,以及其他优势,因此我们希望保留它.现在,我们正面临一些问题,我们已经在主干外测试了一些实验宏.首先,让我们展示一个名为Cake的虚拟系统:

trait APiece {
  class A
}

trait BPiece { this: APiece => 
  def aMacro(a: A): Unit = () /* macro ??? */
}

trait CPiece { this: APiece with BPiece =>
  def aMacroInvoker = aMacro(new A)
}

class Cake { this: APiece with BPiece with CPiece => }
Run Code Online (Sandbox Code Playgroud)

APiece定义了一个类,BPiece应该是一个使用APiece定义类的宏,最后,CPiece调用宏.我说BPiece应该是一个宏,因为我无法为它编写实现代码.我尝试了几种方法,但我总是崩溃以下错误:

"macro implementation must be in statically accessible object"
Run Code Online (Sandbox Code Playgroud)

读取宏代码可以猜测将宏封装在静态模块中是必要的.有没有办法部署使用系统结构的宏?

Eug*_*ako 4

幸运的是,有一个简单的方法可以解决您的问题。

但首先,让我回顾一下。在第一个原型中,宏的定义如下:def macro aMacro(a: A): Unit = ...。我们在准备 SIP 时取得的重大突破之一是将宏定义(宏的公共面)和宏实现(托管宏逻辑的树形转换器)分开。我花了一段时间才意识到这有多酷,但现在每次我编写宏声明时我都会欣喜若狂。

那么,回到你的问题。当然,宏实现必须是静态可访问的(否则,编译器将无法在编译期间加载和调用它们)。然而宏定义没有这个限制,所以你可以这样写定义:

trait BPiece { this: APiece => 
  def aMacro(a: A): Unit = macro Macros.aMacro
}
Run Code Online (Sandbox Code Playgroud)

从定义中引用的宏实现可以放入您想要的任何对象中,甚至放入不同的编译单元中。

A唯一缺少的一块拼图是我们如何从实现中引用,因为A是在蛋糕内部定义的。最简单的方法是使aMacro并依赖类型推断:

(更新:要使该示例在 2.10.0-M7 中运行,需要将 c.TypeTag 替换为 c.AbsTypeTag;要使该示例在 2.10.0-RC1 中运行,需要将 c.AbsTypeTag 替换为 c.WeakTypeTag )

trait BPiece { this: APiece =>
  def aMacro[A](a: A): Unit = macro Macros.aMacro[A]
}

object Macros {
  def aMacro[A: c.TypeTag](c: Context)(a: c.Expr[A]): c.Expr[Unit] = c.literalUnit
}
Run Code Online (Sandbox Code Playgroud)

但是,这不会让您使用reify,因为对于宏实现来说,A它只是一个没有任何成员的类型参数。如果您想从宏中返回特定于蛋糕的内容,也会出现问题,但让我们在出现问题时处理它们。如果需要,请提交后续问题。

  • 我不认为这能解决他的问题,我也不认为任何事情都能解决。蛋糕图案的本质——你应该知道!:-) -- 能够在“客户端”代码中选择您想要的层。如果`Macros`是静态的,你就不能随意切换它。您可以切换源文件或类文件,但不能编写这样的代码:“这将使用此处的宏,而那将使用此处的宏”。 (2认同)