Title: SDL Lesson 16 - 関数ポインタ使う
今回のレッスンでは、関数の外側で定義されているコードを関数の内側から参照できる、便利な関数ポインタの使い方を説明します。
ファイルの作成
lesson16.properties
ダウンロード --> @1
ここでは新しく「lesson16」というビューを作成することにします。まずはビューの定義ファイル lesson16.properties を、プラグインの config/views/all に作成します。
テキストエディタで開いて次のように記述し、保存します。
sdl=com.traction.sdl.tutorial.lesson16
lesson16.sdl
ダウンロード --> @2
ビューの定義ファイル lesson16.properties で指定された lesson16.sdl を com/traction/sdl/tutorial に作成します。
テキストエディタで開いて次のように記述し、保存します。(文字エンコードは UTF-8 にしてください)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>SDL Tutorial</title>
<html.css url="/html/css/sdllessons/styles.css" />
</head>
<body>
<h1>関数ポインタ</h1>
<h2>例 (1) - 独自のポインタを定義&使用</h2>
<var.set name="foo" value="hoge" />
<div>(1) 変数 foo の値は ${foo} です。</div>
<var.set name="*pointer-foo"><#display-foo /></var.set>
<div>(2) 関数ポインタ pointer-foo の値は関数「display-foo」の返り値 <*pointer-foo /> です。</div>
<#hoge />
<hr>
<h2>例 (2) - 特殊な <code>*yield</code> を使用</h2>
<#display-entries type="rchron">
<div class="entry">__entry.tractionid__: __entry.title__</div>
</#display-entries>
</body>
</html>
<sdl.function name="display-foo">
${foo}
</sdl.function>
<sdl.function name="hoge">
<var.set name="foo" value="piyo" />
<!--- 関数ポインタ「pointer-foo」を実行します。
関数ポインタ「pointer-foo」は、関数「display-foo」を実行して変数「foo」の値を取得します。
この時点では、変数「foo」には値「piyo」が代入されているので、関数「display-foo」は「piyo」を返します。
よって、下記の関数ポインタ「pointer-foo」は「piyo」を返します。 -->
<div>(3) 関数「hoge」内の関数ポインタ pointer-foo の値は、関数「display-foo」の返り値 <*pointer-foo /> です。</div>
</sdl.function>
<sdl.function name="display-entries">
<entries type="${type}" proj="*" max="5">
<!--- 関数を呼び出すときの開始タグと終了タグで囲まれていた内容を
関数内で <*yield /> タグを使って実行できます。 -->
<*yield />
</entries>
</sdl.function>
動作確認
キャッシュのクリア
sdl ファイルや properties ファイルを設置、編集した後は、必ずサーバーセットアップ > 一般 > サーバー管理 ページの [キャッシュのクリア] をクリックします。
ビューの表示
TeamPage の検索ボックスに /type lesson16
と入力して Enter キーを押すと、下図のビューが表示されます。
解説
関数ポインタとは?
関数ポインタとは、「関数の外側で定義されたモノを関数の中から参照できる仕組み」です。
- 一般的な変数と同じように使えます。(
<var.set name="..." value="..." />
などが使えます)
- 関数ポインタの名前は必ず半角アスタリスク記号 (*) で始めます。
では、上記コードを元にどのような動作になるのかを見ていきましょう。
ローカル変数「foo」に値「hoge」を代入
上記コードの 13 行目で、ローカル変数「foo」に値「hoge」を代入しています。
<var.set name="foo" value="hoge" />
よって、14 行目の ${foo}
の部分は「hoge」となり、スクリーンショットにあるように、行全体は「(1) 変数 foo の値は hoge です。」となります。
<div>(1) 変数 foo の値は ${foo} です。</div>
関数ポインタ「*pointer-foo」に関数「display-foo」の返り値を代入
16 行目では <var.set />
タグが使われていますが、名前が半角アスタリスク記号で始まることから、これは関数ポインタであることがわかります。
そして、開始タグと終了タグの間で関数「display-foo」を実行し、実行結果を値として代入しています。
<var.set name="*pointer-foo"><#display-foo /></var.set>
関数「display-foo」は 30 行目 〜 32 行目で次のように定義されており、単純にローカル変数「foo」の値を返します。
<sdl.function name="display-foo">
${foo}
</sdl.function>
したがって、関数ポインタ「*pointer-foo」には、関数ポインタ「*pointer-foo」を実行したときのローカル変数「foo」の値「hoge」が代入されます。
その結果、17 行目(下記)の <*pointer-foo /> 部分は「hoge」となり、行全体は「(2) 関数ポインタ pointer-foo の値は関数「display-foo」の返り値 hoge です。」となります。
<div>(2) 関数ポインタ pointer-foo の値は関数「display-foo」の返り値 <*pointer-foo /> です。</div>
関数「hoge」の中から関数ポインタ「*pointer-foo」を参照
19 行目では関数「hoge」を実行しています。
<#hoge />
関数「hoge」は、34 行目 〜 41 行目で、次のように定義されています。
<sdl.function name="hoge">
<var.set name="foo" value="piyo" />
<!--- 関数ポインタ「pointer-foo」を実行します。
関数ポインタ「pointer-foo」は、関数「display-foo」を実行して変数「foo」の値を取得します。
この時点では、変数「foo」には値「piyo」が代入されているので、関数「display-foo」は「piyo」を返します。
よって、下記の関数ポインタ「pointer-foo」は「piyo」を返します。 -->
<div>(3) 関数「hoge」内の関数ポインタ pointer-foo の値は、関数「display-foo」の返り値 <*pointer-foo /> です。</div>
</sdl.function>
35 行目で、変数「foo」に値「piyo」を代入しています。関数実行時の変数「foo」の値は「hoge」でしたが、ここで「piyo」に変わります。
<var.set name="foo" value="piyo" />
40 行目で関数ポインタ「*pointer-foo」を参照しています。
<div>(3) 関数「hoge」内の関数ポインタ pointer-foo の値は、関数「display-foo」の返り値 <*pointer-foo /> です。</div>
この時点の前までは、上記のとおり、関数ポインタ「*pointer-foo」には関数「display-foo」の返り値「hoge」が代入されていました。
しかし、この時に関数ポインタ「*pointer-foo」を参照すると、再び関数「display-foo」を実行され、この時点での変数「foo」の値が返されます。
この時点では変数「foo」には値「piyo」が代入されているので、関数「display-foo」は値「piyo」を返し、関数ポインタ「*pointer-foo」も値「piyo」を返すことになります。
その結果、40 行目全体は、スクリーンショットのとおり、「(3) 関数「hoge」内の関数ポインタ pointer-foo の値は、関数「display-foo」の返り値 piyo です。」となります。
特殊な関数ポインタ *yield の使い方
関数ポインタ「*yield」を使うと、関数を <#関数名>...</#関数名>
で実行したときの、開始タグと終了タグの間に記述されていた内容を参照できます。
上記のコードでは、23 行目 〜 25 行目で次のようにして関数「display-entries」を実行しています。
<#display-entries type="rchron">
<div class="entry">__entry.tractionid__: __entry.title__</div>
</#display-entries>
関数「display-entries」は、43 行目 〜 49 行目で次のように定義されています。
<sdl.function name="display-entries">
<entries type="${type}" proj="*" max="5">
<!--- 関数を呼び出すときの開始タグと終了タグで囲まれていた内容を
関数内で <*yield /> タグを使って実行できます。 -->
<*yield />
</entries>
</sdl.function>
<entries>...<?entries>
タグで記事を取得する処理をループで実行し、その時に関数ポインタである <*yield>
タグを使って開始タグと終了タグの間に記述されていた内容を参照します。
その結果、記事 1 件ごとに次のコード(24 行目)が実行され、各記事の ID とタイトルが画面に表示されます。
<div class="entry">__entry.tractionid__: __entry.title__</div>
__entry.tractionid__
や __entry.title__
は <entries>...</entries>
タグの中で正しく動作します。<entries>...</entries>
の外側に記述しても記事 ID やタイトルは取得できません。
<#関数名>__entry.title__</#関数名>
というコードを見ると、「あれ? __entry.title__
タグが <entries>...</entries>
の中に書かれていないぞ。この __entry.title__
の書き方では記事タイトルを取得できないのでは?」と思うかもしれません。
この推測はある意味正しいです。しかし、関数の中で <*yield />
を <entries>...</entries>
タグの中に記述すると、その時点で __entry.title__
タグが参照され、記事タイトルを取得できます。
まとめ
1. 関数ポインタの名前は半角アスタリスク記号で始まる。
2. 関数内で関数ポインタを参照すると、その時点で関数ポインタが実行されるような形になり、その時点での値を取得できる。
3. 関数ポインタ <*yield />
は特殊な関数ポインタで、<#関数名>...</#関数名>
として実行された関数の、開始タグと終了タグの間に記述されている内容を参照できる。