2

我有几个这样的 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指令行为来实现这个?

4

1 回答 1

5

Velocity 是一个模板引擎,而不是一种适当的编程语言,因此要掌握它的工作原理有点困难。

宏不像 Java 或 C 中的函数,这意味着调用宏不会在堆栈上为局部变量创建新段;速度与上下文一起工作,大多数时候只有一个全局上下文。

尽管如此,还是有两种处理局部变量的方法:

  1. 有一个velocimacro.context.localscope配置参数可以防止从宏中更改全局变量;请注意,此设置已弃用,将在 Velocity 2.0 中删除
  2. 如果启用配置参数,则可以将该$macro变量用作私有变量的本地容器macro.provide.scope.control

尽管如此,还有另一个问题会阻止您的代码正确运行:Velocity 宏主要作为 call-by-macro 扩展工作,这意味着传递给宏的主体不会先被评估,然后再传递给宏;它将在执行嵌套宏时动态评估。代码的行为如下:

#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
于 2012-09-21T08:23:15.047 回答