2012-06-28 87 views
5

我必須將一些宏集成到使用蛋糕模式的項目中。這種模式使我們能夠避免大量的進口以及其他優勢,所以我們希望保留它。現在,我們遇到了一些我們在主幹外測試的實驗宏的問題。首先,讓我們展現一個虛擬的命名蛋糕系統:是否可以集成Cake-Pattern和Macros?

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 => } 

每人定義一個類,BPiece應該是它採用的每人定義的類的宏,最後,CPiece調用宏。我說過,BPiece應該是一個宏,因爲我無法爲它編寫實現代碼。我嘗試了好幾種方法,但我總是與以下錯誤崩潰:

"macro implementation must be in statically accessible object" 

macros code一個可以猜測,這是neccesary附上宏觀靜態模塊中。有沒有辦法部署一個使用系統結構的宏?

回答

4

幸運的是,您的問題有一個簡單的解決方案。

但是首先讓我回顧一下。在第一個原型中,宏定義如下:def macro aMacro(a: A): Unit = ...。我們在準備SIP時所取得的重大突破之一是將宏定義(宏的公開面)與宏實現(承載宏邏輯的樹變換器)分開。我花了一段時間才意識到這是多麼的酷,但是現在每當我寫一個宏觀聲明時,我都會很高興。

所以,回到你的問題。當然,宏實現必須是靜態可訪問的(否則編譯器將無法在編譯期間加載和調用它們)。但是宏定義沒有這個限制,所以你可以寫這樣的定義:

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

是從定義中提到的可以放進你希望的任何對象宏實現,甚至爲不同的編譯單元。

唯一缺失的難題是我們將如何參考實施中的A,因爲A是在蛋糕內部定義的。最簡單的方法是製作aMacro通用並依賴類型推斷:

(更新:爲了使此示例在2.10.0-M7中工作,您需要用c.AbsTypeTag替換c.TypeTag;以使此示例在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僅僅是一個類型參數,而不任何成員。如果你想從宏中返回一些特定於蛋糕的東西,也會遇到問題,但是當它們出現時,我們就來處理它們。如果需要,請提交後續問題。

+2

我不認爲這解決了他的問題,我不認爲會有什麼。蛋糕模式的本質 - 就像你應該知道的那樣! :-) - 能夠在「客戶端」代碼中選擇你想要的圖層。如果'宏'是靜態的,則不能隨意切換。你可以切換源文件或類文件,但是你不能編寫代碼說「這將使用來自這裏的宏,並且將使用來自那裏的宏」。 –

+0

太好了,我認爲會出現新的問題,但我現在可以繼續使用此解決方案。非常感謝你!Daniel,我們的系統不會像宏一樣純粹(蛋糕模式)。我們只允許客戶決定他是否要使用它們。所以,我希望這樣做夠好。 – jeslg

+0

@ DanielC.Sobral雖然我的想法是在一個蛋糕裏面聲明一個宏。如果您有不同的圖層來定義指向不同宏實現的宏,您可以根據需要在它們之間切換並獲得不同的行爲。 –

相關問題