2014-02-25 96 views
2

我已經定義了下面的宏從當前位置開始的文件,線和對象/類: http://pastebin.com/UsNLemnK斯卡拉宏快捷

使用SBT,我已經定義了兩個項目,以先編譯宏,然後實際的項目使用這些宏。

這些宏的目的是要在一個日誌方法中使用:

def log(msg: Any, srcFile: String = "", srcLine: String = "", srcClass:String = "") 

然後我使用該日誌方法如下:

log(msg, s"$F_",s"$L_",s"$C_") 

其中F_,L_和C_是在宏中定義。現在

,我想創建一個快捷方式,以避免這種情況的樣板,只是稱:

log(msg) 

應自動

log(msg, s"$F_",s"$L_",s"$C_") 

代替我可以定義一個宏來做到這一點:

def log_(msg: String) : Unit = macro logImpl 
def logImpl(c: Context)(msg: c.Expr[String]): c.Expr[Unit] = { 
    import c.universe._ 
    reify(log(msg.splice, srcFile=s"$F_", srcLine=s"$L_", srcClass=s"$C_")) 
} 

但同樣,這個宏所需要的項目,其中日誌之前被編譯函數本身被定義...所以我不明白如何解決編譯依賴關係週期...

任何有關如何做到這一點的建議? 謝謝

+0

什麼阻止你將'log'函數移動到宏項目​​? –

+0

由於日誌功能相當複雜,它並不覺得「乾淨」......我必須將許多部件從我的核心項目移至宏觀項目。我希望能有更好的方式 – borck

回答

2

除非使用macro annotations(它必然會顯着地改變你的API的語法),你必須面對的問題是你需要類型檢查你的日誌函數的標識符。

因爲你不能導入整個log實施,一個解決辦法是:

  • 包裝方法爲特質,
  • 在「宏」項目中定義這個特質,
  • 隱含參數在你的「主」項目添加到log_方法,
  • ,創建此特徵的實現,並instan在你想要使用宏(例如在包對象中)使用log_的任何地方都可以看到implicit val

當然,你也可以使用一個簡單的FunctionN這裏,避免特徵定義和實現,但這樣一來,你會避免與其他同類型的implicits潛在衝突。

一般情況下,你的代碼將類似於以下:

//"macro" project 
trait EncapsulatingTrait { 
    def yourMethod(...) 
} 

object Macros { 
    def myMacro(...)(implicit param: EncapsulatingTrait) = macro myMacroImpl 
    def myMacroImpl(c: Context)(...) 
          (param: c.Expr[EncapsulatingTrait]): c.Expr[...] = { 
    import c.universe._ 
    reify(param.splice.yourMethod(...)) 
    } 
} 

//-------------------------- 
//"main" project 
class Impl extends EncapsulatingTrait { 
    def yourMethod(...) 
} 

... 

implicit val defaultParam = new Impl 

import Macros.myMacro 

myMacro(...) 

在您的具體情況,這裏的實現可能看起來怎麼樣:

​​

(請注意,我必須糾正log_和tw的簽名讓宏調用一下)

+0

完美謝謝。還有一個問題,如果我在最高級別的包對象中聲明瞭隱式val,我如何才能讓所有兒童包都可以訪問它? – borck

+1

沒關係,我在這裏找到了答案:http://stackoverflow.com/questions/2830248/what-are-nested-unnested-packages-in-scala-2-8 – borck