summaryrefslogtreecommitdiffhomepage
path: root/services/blog/public/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range
diff options
context:
space:
mode:
Diffstat (limited to 'services/blog/public/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range')
-rw-r--r--services/blog/public/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/index.html184
1 files changed, 184 insertions, 0 deletions
diff --git a/services/blog/public/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/index.html b/services/blog/public/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/index.html
new file mode 100644
index 00000000..39450d30
--- /dev/null
+++ b/services/blog/public/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/index.html
@@ -0,0 +1,184 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2024 nsfisis">
+ <meta name="description" content="Go言語の text/template における with や range は &quot;.&quot; を上書きする。これらの内側から外側の &quot;.&quot; にアクセスする方法を調べた。">
+ <meta name="keywords" content="Go">
+ <meta property="og:type" content="article">
+ <meta property="og:title" content="【Go】 text/template の with や range の内側から外側の &quot;.&quot; にアクセスする|REPL: Rest-Eat-Program Loop">
+ <meta property="og:description" content="Go言語の text/template における with や range は &quot;.&quot; を上書きする。これらの内側から外側の &quot;.&quot; にアクセスする方法を調べた。">
+ <meta property="og:site_name" content="REPL: Rest-Eat-Program Loop">
+ <meta property="og:locale" content="ja_JP">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>【Go】 text/template の with や range の内側から外側の &quot;.&quot; にアクセスする|REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=9513229b52eb2041b99ba1b959305633">
+ </head>
+ <body class="single">
+ <header class="header">
+ <div class="site-logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </div>
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">【Go】 text/template の with や range の内側から外側の &quot;.&quot; にアクセスする</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/go/">Go</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section id="changelog">
+ <h2><a href="#changelog">更新履歴</a></h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2024-08-19">2024-08-19</time>: 公開
+ </li>
+ </ol>
+ </section>
+ <section id="section--tldr">
+ <h2><a href="#section--tldr">TL;DR</a></h2>
+ <p>
+ 常にトップレベルを指す特殊変数 <code>$</code> を使えばよい。
+ </p>
+ </section>
+ <section id="section--intro">
+ <h2><a href="#section--intro">はじめに</a></h2>
+ <p>
+ Go には、標準ライブラリにテンプレートライブラリ <code>text/template</code> がある。この <code>text/template</code> における制御構造、<code>with</code> と <code>range</code> は次のように使われる。
+ </p>
+ <div class="codeblock">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span># {{ .Title }}</span></span>
+<span class="line"><span></span></span>
+<span class="line"><span># User</span></span>
+<span class="line"><span></span></span>
+<span class="line"><span>{{ with .User }}</span></span>
+<span class="line"><span> {{ .Name }} ({{ .ID }})</span></span>
+<span class="line"><span>{{ end }}</span></span>
+<span class="line"><span></span></span>
+<span class="line"><span># Items</span></span>
+<span class="line"><span></span></span>
+<span class="line"><span>{{ range .Items }}</span></span>
+<span class="line"><span> - {{ . }}</span></span>
+<span class="line"><span>{{ end }}</span></span></code></pre>
+ </div>
+ <p>
+ <code>text/template</code> の <code>.</code> は、現在の操作対象を表す特殊なオブジェクトである。
+ </p>
+ <p>
+ <code>with</code> や <code>range</code> は、<code>.</code> を変更する効果を持つ。<code>with</code> は引数に渡されたオブジェクトを <code>.</code> へセットして、内部のテンプレートを実行する。<code>range</code> は引数に渡されたイテレート可能なオブジェクトに対し、それぞれの要素を <code>.</code> へセットして、要素の個数だけ内部のテンプレートを実行する。
+ </p>
+ <p>
+ つまりこのテンプレートは、次のような構造をレンダリングしている (<code>Execute()</code> の第2引数)。
+ </p>
+ <div class="codeblock">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">tmpl.</span><span style="color:#6F42C1">Execute</span><span style="color:#24292E">(out, </span><span style="color:#6F42C1">Params</span><span style="color:#24292E">{</span></span>
+<span class="line"><span style="color:#24292E"> Title: </span><span style="color:#032F62">"foo"</span><span style="color:#24292E">,</span></span>
+<span class="line"><span style="color:#24292E"> User: </span><span style="color:#6F42C1">User</span><span style="color:#24292E">{</span></span>
+<span class="line"><span style="color:#24292E"> ID: </span><span style="color:#005CC5">123</span><span style="color:#24292E">,</span></span>
+<span class="line"><span style="color:#24292E"> Name: </span><span style="color:#032F62">"john"</span><span style="color:#24292E">,</span></span>
+<span class="line"><span style="color:#24292E"> },</span></span>
+<span class="line"><span style="color:#24292E"> Items: []</span><span style="color:#D73A49">string</span><span style="color:#24292E">{</span></span>
+<span class="line"><span style="color:#032F62"> "hoge"</span><span style="color:#24292E">,</span></span>
+<span class="line"><span style="color:#032F62"> "piyo"</span><span style="color:#24292E">,</span></span>
+<span class="line"><span style="color:#032F62"> "fuga"</span><span style="color:#24292E">,</span></span>
+<span class="line"><span style="color:#24292E"> },</span></span>
+<span class="line"><span style="color:#24292E">})</span></span></code></pre>
+ </div>
+ </section>
+ <section id="section--what-i-want-to-do">
+ <h2><a href="#section--what-i-want-to-do">やりたいこと</a></h2>
+ <p>
+ 今回おこないたいのは、<code>with</code> や <code>range</code> の中で、その外側で使われていたトップレベルのオブジェクトを参照することだ。
+ </p>
+ <div class="codeblock">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>{{ with .User }}</span></span>
+<span class="line"><span> ここから .Title を参照するには?</span></span>
+<span class="line"><span>{{ end }}</span></span>
+<span class="line"><span></span></span>
+<span class="line"><span>{{ range .Items }}</span></span>
+<span class="line"><span> ここから .User を参照するには?</span></span>
+<span class="line"><span>{{ end }}</span></span></code></pre>
+ </div>
+ <p>
+ <code>with</code> や <code>range</code> は、<code>.</code> を自身の対象オブジェクトに変更するので、単に <code>{{ with .User }}</code> の中で <code>.Title</code> と書いても、それは <code>User</code> の <code>Title</code> プロパティを参照しているとみなされる。
+ </p>
+ <p>
+ <code>text/template</code> では変数が使えるので、テンプレートの先頭で
+ </p>
+ <div class="codeblock">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>{{ $params := . }}</span></span></code></pre>
+ </div>
+ <p>
+ とでもしておけば実現は可能である。
+ </p>
+ <p>
+ しかしながら、頻発するシチュエーションにしてはあまりに不恰好である。よりスマートな方法が用意されているはずだ。
+ </p>
+ </section>
+ <section id="section--solution">
+ <h2><a href="#section--solution">解決方法</a></h2>
+ <p>
+ 常にトップレベルを指す特殊変数 <code>$</code> を使えばよい。
+ </p>
+ <div class="codeblock">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>{{ with .User }}</span></span>
+<span class="line"><span> {{ $.Title }}</span></span>
+<span class="line"><span>{{ end }}</span></span>
+<span class="line"><span></span></span>
+<span class="line"><span>{{ range .Items }}</span></span>
+<span class="line"><span> {{ $.User.Name }}</span></span>
+<span class="line"><span>{{ end }}</span></span></code></pre>
+ </div>
+ <p>
+ <code>$</code> は、テンプレートが実行されるときに渡されたオブジェクトを指す。これを使えば現在の <code>.</code> に関係なくトップレベルを参照できる。
+ </p>
+ <p>
+ このことは、<a href="https://pkg.go.dev/text/template#hdr-Variables" rel="noreferrer" target="_blank"><code>text/template</code> の公式ドキュメント</a>にも以下のように記載されている。
+ </p>
+ <blockquote>
+ <p>
+ When execution begins, $ is set to the data argument passed to Execute, that is, to the starting value of dot.
+ </p>
+ </blockquote>
+ </section>
+ <section id="section--reference">
+ <h2><a href="#section--reference">参考</a></h2>
+ <ul>
+ <li>
+ <a href="https://stackoverflow.com/questions/14800204/in-a-template-how-do-you-access-an-outer-scope-while-inside-of-a-with-or-rang" rel="noreferrer" target="_blank">直接の出典である Stack Overflow の回答: <span>In a template how do you access an outer scope while inside of a “with” or “range” scope?</span></a>
+ </li>
+ <li>
+ <a href="https://pkg.go.dev/text/template#hdr-Variables" rel="noreferrer" target="_blank">大元の出典である <code>text/template</code> の公式ドキュメント</a>
+ </li>
+ </ul>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>