2012-09-20 97 views
0

我有一對夫婦的速度宏是這樣的:封閉在Velocity模板的宏

#macro(Alpha) 
    #set($p = 1) 
    #@Beta() 
    $p    // 1 
    $bodyContent 
    #end 
#end 

#macro(Beta $params) 
    #set($p = 2) 
    $p    // 2 
    $bodyContent 
#end 

而我使用它們像這樣:

#set($p = 0) 
#@Alpha(...) 
    $p    // 3 
#end 

我相信,這使得像這樣(忽略格式化):2,2,2

但我想有適當的閉包行爲,包括更多本地範圍的名稱隱藏父範圍名稱。具體來說,標記爲'3'的$ p的使用應該指向值0,'2'指向值2,'1'指向值1.

給定適當的閉包語義,它將打印:2 ,1,0

有沒有什麼辦法得到這個,或者一種實現自定義指令/修改#macro指令行爲的方法來實現這個?

回答

5

Velocity是一個模板引擎,不是一種正確的編程語言,所以掌握它的工作原理有點困難。

宏不像Java或C中的函數,這意味着調用宏不會在堆棧上爲局部變量創建新的段;速度與上下文一起工作,大部分時間只有一個全局上下文。

不過,也有處理局部變量的方法有兩種:

  1. 有阻止改變從宏中的全局變量velocimacro.context.localscope配置參數;注意,此設置已被棄用,並將在速度2.0移除
  2. 可以使用$macro變量作爲私有變量本地容器如果啓用macro.provide.scope.control配置參數

不過,有會阻止另一個問題您的代碼正確運行:Velocity macros work mostly as call-by-macro expansion,這意味着傳遞給宏的主體不會先評估,然後傳遞給宏;它將在嵌套宏執行時動態評估。該代碼的行爲如下:

#macro(Alpha) 
    #set($macro.p = 1) -> $macro refers to Alpha 
    $p -> $p will always be 0, since we're changing a local variable 
    $macro.p -> 1 here 
    $bodyContent -> Here $p is used, and 0 is printed 
    #@Beta() 
    $macro.p -> it is 1 now, but when this line will be actually evaluated, $macro will refer to Beta, so 2 will be printed 
    $bodyContent -> It's the content of the Beta macro, which triggers an infinite recursion; it's not $p as above 
    #end 
#end 

#macro(Beta) 
    #set($macro.p = 2) -> $macro refers to Beta 
    $macro.p -> 2 here 
    $bodyContent -> the $bodyContent that was passed into the $bodyContent is evaluated now, so it causes a recursion 
#end 

#set($p = 0) 
#@Alpha() 
    $p -> Global variable 
#end 
+0

我已閱讀了關於這個神奇的$宏變量,但無法讓它工作,所以非常感謝你的配置屬性。關於按名稱調用的問題,我也意識到了這一點,並且實際上做了一個定製構建,它熱切地評估正文並將其作爲純文本節點傳遞給宏的$!bodyContent(或其配置爲的任何變量)變量。 – gzak

+0

我還有一個跟進問題:除了$ macro之外,還有其他類型的局部變量,例如#foreach指令中的$ foreach。有沒有#if?在文檔中也有一個名爲$ foo(可能作爲示例),它對應於#@ foo()... #end指令中的局部變量。這些範圍的各種配置屬性名稱(特別是#if和示例$ foo中的一個)是什麼? – gzak

+0

所有配置屬性都列在[documentation](http://velocity.apache.org/engine/releases/velocity-1.7/developer-guide.html#Velocity_Configuration_Keys_and_Values)中。 '#if'塊沒有範圍變量。搜索'''somebodymacro> .provide.scope.control'來查看如何爲名爲'#foo'的宏配置像'$ foo'這樣的範圍變量。 –