Closure in Velocity template macros

拜拜、爱过 提交于 2019-12-11 04:58:38

问题


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?


回答1:


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:

  1. 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
  2. You can use the $macro variable as a local container for private variables if you enable the macro.provide.scope.control configuration parameter

Still, 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


来源:https://stackoverflow.com/questions/12519289/closure-in-velocity-template-macros

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!