5

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はクラスを定義し、BPieceは APiece で定義されたクラスを使用するマクロであると想定され、最後にCPieceがマクロを呼び出します。BPiece の実装をコーディングできなかったので、BPiece はマクロであるべきだと言いました。いくつかの方法を試しましたが、常に次のエラーでクラッシュします。

"macro implementation must be in statically accessible object"

マクロ コードを読むと、マクロを静的モジュールに含める必要があることが推測できます。システム構造を使用するマクロを展開する方法はありますか?

4

1 に答える 1

4

幸いなことに、問題に対する簡単な解決策があります。

しかし、最初に、振り返りをさせてください。最初のプロトタイプでは、マクロは次のように定義されていdef macro aMacro(a: A): Unit = ...ました。SIP を準備する際に実現した大きなブレークスルーの 1 つは、マクロ定義 (マクロの公開面) とマクロ実装 (マクロ ロジックをホストするツリー トランスフォーマー) を分離することです。これがいかにクールかを理解するのにしばらく時間がかかりましたが、今ではマクロ宣言を書くたびに喜びに輝いています。

それで、あなたの質問に戻ります。確かに、マクロの実装は静的にアクセスできる必要があります (そうでない場合、コンパイラはコンパイル中にそれらを読み込んで呼び出すことができません)。ただし、マクロ定義にはこの制限がないため、次のように定義を記述できます。

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

定義から参照されるマクロの実装は、別のコンパイル単位であっても、任意のオブジェクトに配置できます。

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
}

reifyただし、これでは を使用できません。マクロの実装Aでは、メンバーを持たない単なる型パラメーターであるためです。マクロからケーキ固有のものを返したい場合にも問題がありますが、それらが発生した場合に対処しましょう。必要に応じて、フォローアップの質問を送信してください。

于 2012-06-28T17:47:54.433 に答える