在Velocity模板宏中关闭 [英] Closure in Velocity template macros
问题描述
我有一个几个Velocity宏,像这样:
#macro(Alpha)
#set $ p = 1)
#@ Beta()
$ p // 1
$ bodyContent
#end
#end
#宏(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指令行为来实现这一点?
解决方案Velocity是一个模板引擎,不是一个合适的编程语言,如何工作。
宏不是Java或C中的函数,意味着调用宏不会在局部变量的堆栈上创建一个新的段;速度适用于上下文,大多数时候只有一个全局上下文。
仍然有两种方法处理局部变量:
- 有
velocimacro.context.localscope
配置参数,阻止在宏内更改全局变量;请注意,此设置已弃用,将在Velocity 2.0中删除
- 您可以使用
$ macro
变量作为私有如果您启用macro.provide.scope.control
配置参数
仍然有另一个问题,会阻止您的代码正常运行: Velocity宏主要作为宏调用扩展,这意味着传递给宏的主体不会先计算,然后传递给宏;当嵌套宏被执行时,它将被动态地评估。代码行为如下:
#macro(Alpha)
#set($ macro.p = 1) - > ; $ macro是指Alpha
$ p - > $ p将始终为0,因为我们正在更改一个局部变量
$ macro.p - > 1 here
$ bodyContent - >这里使用$ p,并且打印0。
#@ Beta()
$ macro.p - >它现在是1,但是当这行将被实际评估时,$ macro将引用Beta,因此2将被打印
$ bodyContent - >它是Beta宏的内容,触发无限递归;它不是$ p如上
#end
#end
#macro(Beta)
#set($ macro.p = 2) - > $ macro是指Beta
$ macro.p - > 2 here
$ bodyContent - >传递给$ bodyContent的$ bodyContent现在被评估,所以它导致递归
#end
#set($ p = 0)
#@ Alpha()
$ p - >全局变量
#end
I've got a couple Velocity macros like this:
#macro(Alpha) #set($p = 1) #@Beta() $p // 1 $bodyContent #end #end #macro(Beta $params) #set($p = 2) $p // 2 $bodyContent #end
And I'm using them like so:
#set($p = 0) #@Alpha(...) $p // 3 #end
I believe this renders like so (ignore formatting): 2, 2, 2
But I'd like to have proper closure behavior, including more locally scoped names hiding parent scope names. In particular, the usage of $p labelled '3' should refer to the value 0, '2' to the value 2, and '1' to the value 1.
Given proper closure semantics, it would print: 2, 1, 0
Is there any way to get this, or a way to implement a custom directive / modify #macro directive behavior to achieve this?
解决方案Velocity is a templating engine, not a proper programming language, so it's a bit harder to grasp how it works.
Macros are not functions like in Java or C, meaning that invoking a macro isn't going to create a new segment on the stack for local variables; velocity works with a context, and most of the time there's just one global context.
Still, there are two ways of dealing with local variables:
- There's the
velocimacro.context.localscope
configuration parameter that prevents changing global variables from within macros; note that this setting is deprecated and will be removed in Velocity 2.0- You can use the
$macro
variable as a local container for private variables if you enable themacro.provide.scope.control
configuration parameterStill, there's another problem that would prevent your code from running correctly: Velocity macros work mostly as call-by-macro expansion, which means that the body passed to a macro isn't evaluated first, then passed to the macro; it will be evaluated dynamically when the nested macro is executed. The code behaves as:
#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
这篇关于在Velocity模板宏中关闭的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!