こんにちは!FreeMarker、書いてますか!
僕はあんまり書いてません!
書いてませんけど、書いてる人から質問されて挙動を調べたので覚書です!
もうめんどくさいのでFreeMarkerじゃなくてftlって書きますけど、ftlにはデフォルト値演算子があります。
${str!} ${str!"hoge"} ${num!0}
こういうの。
FreeMarker Manual - Expressions
上みたいな感じで純粋に文字列を表示する分には特に困りません。
むしろ以下のような書き方をしなくて済むので便利です。
<#if str??>${str}<#else>hoge</#if>
ちょっと困るのはこいつをifの中で使う場合です。
たとえばnumという変数が存在しない、または0の場合にtrueをそれ以外はfalseを返す場合を考えます。
上の書き方を踏まえて単純に書くとこんなかんじですね。
<#if num!0 == 0> true </#if>
でもこれだと以下のようなエラーを吐きます。
Error on line 2, column 6 in Expecting a boolean (true/false) expression here Expression num!0 == 0 does not evaluate to true/false it is an instance of freemarker.template.SimpleNumber
お前が指定したやつtrue/falseで評価できねーから!みたいな。かんじの。
あたかもこんなの書いたような感じのエラーです。
<#if 0>
ちゃんと数値比較してほしいので以下のように変更してみます。
<#if (num!0) == 0> true </#if>
エラーが出なくなりました!
次に数値じゃなくて文字列でやってみます。
<#if str!"hoge" == "hoge"> true </#if>
案の定以下のようなエラーを吐きます。
Error on line 2, column 6 in Expecting a boolean (true/false) expression here Expression str!"hoge" == "hoge" does not evaluate to true/false it is an instance of freemarker.template.SimpleScalar
同じような感じなので同じように直してみます。
<#if (str!"hoge") == "hoge"> true </#if>
エラーが出なくなりました!
つまり、デフォルト演算子をifの中で使う場合、デフォルト値ごと括弧でくくってやる必要があるわけですね。
beanの中のnumって値に対してやる場合は以下のようにしてやらないといけないわけです。
<#if ((bean.str)!0) == 0> true </#if>
めんどい。
ちなみにエラーが出てたやつらですが、値が存在しない場合はエラー吐かないのでたちが悪いです。こわい。
あとデフォルト値演算子使うけどデフォルト値を明示的に指定しないことも出来るんですが、stringの比較の場合はこれが使えて、かつ括弧で囲わなくてもエラーが出なかったりします。
<#if str! == "hoge"> true </#if>
もちろんこの場合は上の例と違ってstrが存在しないときfalseになりますけど。
余談ですが、じわじわブックマーク数が伸びたり伸びてなかったりする前に書いたエントリ。
FreeMarkerおぼえがき - するめとめがね
この中でデフォルト演算子でbooleanを扱うときは括弧で囲わないと必ず宣言された値になるみたいなことを書いてます。
こんなかんじ。
<#assign hoge = true> trueを表示 <#if hoge!false == true> true </#if> これもtrueを表示 <#if hoge!false == false> true </#if>
これも多分この問題の関係なんじゃないかなーと思ったりしました。
内部的には以下のように解釈されてるんじゃないかなー的な。
こう書いても <#if hoge!false == true> true </#if> 値が存在する場合はこう解釈される <#if hoge> true </#if>
ソース読んでないので想像ですけど!
日本ってftlのドキュメント少ないのでもうちょっと書きたいんですけど、大してネタないんですよね。
また何かあったら書こう。あったら。