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 つだけです。

それでも、ローカル変数を扱う方法は 2 つあります。

  1. velocimacro.context.localscopeマクロ内からグローバル変数を変更できないようにする構成パラメーターがあります。この設定は非推奨であり、Velocity 2.0 で削除されることに注意してください。
  2. 構成パラメーター$macroを有効にすると、変数をプライベート変数のローカル コンテナーとして使用できます。macro.provide.scope.control

それでも、コードの正常な実行を妨げる別の問題があります。Velocity マクロはほとんどの場合、マクロ呼び出しによる展開として機能します。これは、マクロに渡される本体が最初に評価されず、次にマクロに渡されることを意味します。ネストされたマクロが実行されると、動的に評価されます。コードは次のように動作します。

#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 に答える