简体   繁体   English

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

[英]Is it possible to integrate Cake-Pattern and Macros?

I must integrate some macros in a project which is using a cake-pattern. 我必须在一个使用蛋糕模式的项目中集成一些宏。 That pattern allowed us to avoid zillions of imports, among other advantages, so we would like to keep it. 这种模式使我们能够避免数以万计的进口,以及其他优势,因此我们希望保留它。 Now, we are facing a problem with some experimental macros we have been testing outside the trunk. 现在,我们正面临一些问题,我们已经在主干外测试了一些实验宏。 First, let's show a dummy system named Cake: 首先,让我们展示一个名为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 => }

APiece defines a class, BPiece is supposed to be a macro which uses the APiece defined class, and finally, CPiece invokes the macro. APiece定义了一个类, BPiece应该是一个使用APiece定义类的宏,最后, CPiece调用宏。 I said that BPiece was supposed to be a macro since I was unable to code an implementation for it. 我说BPiece应该是一个宏,因为我无法为它编写实现代码。 I have tried several ways but I always crash with the following error: 我尝试了几种方法,但我总是崩溃以下错误:

"macro implementation must be in statically accessible object"

Reading the macros code one can guess that it is neccesary to enclose the macro in a static module. 读取宏代码可以猜测将宏封装在静态模块中是必要的。 Is there any way to deploy a macro which uses the system structures? 有没有办法部署使用系统结构的宏?

Luckily there's an easy solution to your problem. 幸运的是,您可以轻松解决问题。

But first, let me give some retrospective. 但首先,让我来回顾一下。 In the very first prototype, macros were defined like that: def macro aMacro(a: A): Unit = ... . 在第一个原型中,宏定义如下: def macro aMacro(a: A): Unit = ... One of the major breakthroughs we've had when preparing a SIP is separating macro definitions (public faces of macros) and macro implementations (tree transformers that host macro logic). 我们在准备SIP时所取得的重大突破之一是分离宏定义(宏的公共面)和宏实现(承载宏逻辑的树变换器)。 It took me a while realize how cool this is, but now I'm glowing with joy every time when I write a macro declaration. 我花了一段时间才意识到它有多酷,但现在每次写宏观声明时我都会高兴得发光。

So, back to your question. 所以,回到你的问题。 Sure, macro implementations have to be statically accessible (otherwise, compiler won't be able to load and invoke them during the compilation). 当然,宏实现必须是静态可访问的(否则,编译器将无法在编译期间加载和调用它们)。 However macro definitions don't have this restriction, so you can write the definition like that: 但是宏定义没有这个限制,所以你可以像这样编写定义:

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

Macro implementation that is referred to from the definition can be put into whatever object you wish, even into a different compilation unit. 从定义中引用的宏实现可以放入您希望的任何对象中,甚至可以放入不同的编译单元中。

The only missing piece of puzzle is how we're going to refer to A from the implementation, because A is defined inside a cake. 唯一缺失的难题是我们将如何从实现中引用A ,因为A是在蛋糕内定义的。 The simplest way would be to make aMacro generic and rely on type inference: 最简单的方法是使aMacro通用并依赖于类型推断:

(update: to make this example work in 2.10.0-M7, you need to replace c.TypeTag with c.AbsTypeTag; to make this example work in 2.10.0-RC1, c.AbsTypeTag needs to be replaced with c.WeakTypeTag) (更新:要使此示例在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
}

This won't let you use reify , though, because for a macro implementation A is just a type parameter without any members. 但是,这不会让你使用reify ,因为对于宏实现, A只是一个没有任何成员的类型参数。 There are also going to be problems if you'll want to return something cake-specific from the macro, but let's deal with them when they arise. 如果你想要从宏中返回特定于蛋糕的东西,也会出现问题,但是当它们出现时让我们处理它们。 Please, submit follow-up questions if you need to. 如果需要,请提交后续问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM