关闭Velocity模板宏

时间:2012-09-20 19:09:53

标签: templates closures velocity

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

1 个答案:

答案 0 :(得分:5)

Velocity是一个模板引擎,而不是一种正确的编程语言,所以要掌握它是如何工作的有点困难。

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

但是,有两种方法可以处理局部变量:

  1. velocimacro.context.localscope配置参数阻止在宏中更改全局变量;请注意,此设置已弃用,将在Velocity 2.0
  2. 中删除
  3. 如果启用$macro配置参数
  4. ,则可以将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