我有一些像这样的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
但我希望有适当的关闭行为,包括隐藏父范围名称的更多本地范围名称。特别是使用$ p标记为' 3'应该参考值0,' 2'值为2,' 1'值为1。
给定正确的闭包语义,它将打印:2,1,0
有没有办法得到这个,或者实现自定义指令/修改#macro指令行为来实现这个目的?
答案 0 :(得分:5)
Velocity是一个模板引擎,而不是一种正确的编程语言,所以要掌握它是如何工作的有点困难。
宏不是Java或C中的函数,这意味着调用宏不会在堆栈上为局部变量创建新段;速度适用于上下文,大多数时候只有一个全局上下文。
但是,有两种方法可以处理局部变量:
velocimacro.context.localscope
配置参数阻止在宏中更改全局变量;请注意,此设置已弃用,将在Velocity 2.0 $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