diff options
| author | nsfisis <nsfisis@gmail.com> | 2024-08-19 02:08:27 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2024-08-19 02:24:06 +0900 |
| commit | 41203279e88ceb19e50fc47b9781cd57afc696cc (patch) | |
| tree | 4506fb5404c431413394fcc9e08230d214280fec /vhosts/blog/public/posts | |
| parent | 5f8709982bd83ab2abba68c00b33f6c1494d5d0b (diff) | |
| download | nsfisis.dev-41203279e88ceb19e50fc47b9781cd57afc696cc.tar.gz nsfisis.dev-41203279e88ceb19e50fc47b9781cd57afc696cc.tar.zst nsfisis.dev-41203279e88ceb19e50fc47b9781cd57afc696cc.zip | |
feat(blog/content): new post /posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/
Diffstat (limited to 'vhosts/blog/public/posts')
3 files changed, 217 insertions, 1 deletions
diff --git a/vhosts/blog/public/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/index.html b/vhosts/blog/public/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/index.html new file mode 100644 index 00000000..25f47189 --- /dev/null +++ b/vhosts/blog/public/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/index.html @@ -0,0 +1,193 @@ +<!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="© 2024 nsfisis"> + <meta name="description" content="Go言語の text/template における with や range は "." を上書きする。これらの内側から外側の "." にアクセスする方法を調べた。"> + <meta name="keywords" content="Go"> + <meta property="og:type" content="article"> + <meta property="og:title" content="【Go】 text/template の with や range の内側から外側の "." にアクセスする|REPL: Rest-Eat-Program Loop"> + <meta property="og:description" content="Go言語の text/template における with や range は "." を上書きする。これらの内側から外側の "." にアクセスする方法を調べた。"> + <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 の内側から外側の "." にアクセスする|REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/style.css?h=0656606dcfb3f6fa094a976e05df9007"> + <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> + </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 の内側から外側の "." にアクセスする</h1> + <ul class="post-tags"> + <li class="tag"> + <a href="/tags/go/">Go</a> + </li> + </ul> + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</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> + + <pre class="highlight"><code># {{ .Title }} + +# User + +{{ with .User }} + {{ .Name }} ({{ .ID }}) +{{ end }} + +# Items + +{{ range .Items }} + - {{ . }} +{{ end }}</code></pre> + + <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> + + <pre class="highlight" language="go"><code class="highlight">tmpl.Execute(out, Params{ + Title: <span class="hljs-string">"foo"</span>, + User: User{ + ID: <span class="hljs-number">123</span>, + Name: <span class="hljs-string">"john"</span>, + }, + Items: []<span class="hljs-type">string</span>{ + <span class="hljs-string">"hoge"</span>, + <span class="hljs-string">"piyo"</span>, + <span class="hljs-string">"fuga"</span>, + }, +})</code></pre> + </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> + + <pre class="highlight"><code>{{ with .User }} + ここから .Title を参照するには? +{{ end }} + +{{ range .Items }} + ここから .User を参照するには? +{{ end }}</code></pre> + + <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> + + <pre class="highlight"><code>{{ $params := . }}</code></pre> + + <p> + とでもしておけば実現は可能である。 + </p> + + <p> + しかしながら、頻発するシチュエーションにしてはあまりに不恰好である。よりスマートな方法が用意されているはずだ。 + </p> + </section> + + <section id="section--solution"> + <h2><a href="#section--solution">解決方法</a></h2> + <p> + 常にトップレベルを指す特殊変数 <code>$</code> を使えばよい。 + </p> + + <pre class="highlight"><code>{{ with .User }} + {{ $.Title }} +{{ end }} + +{{ range .Items }} + {{ $.User.Name }} +{{ end }}</code></pre> + + <p> + <code>$</code> は、テンプレートが実行されるときに渡されたオブジェクトを指す。 これを使えば現在の <code>.</code> に関係なくトップレベルを参照できる。 + </p> + + <p> + このことは、<a href="https://pkg.go.dev/text/template#hdr-Variables"><code>text/template</code> の公式ドキュメント</a>にも以下のように記載されている。 + </p> + + <blockquote> + When execution begins, $ is set to the data argument passed to Execute, that is, to the starting value of dot. + </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">直接の出典である Stack Overflow の回答: "In a template how do you access an outer scope while inside of a "with" or "range" scope?"</a> + </li> + + <li> + <a href="https://pkg.go.dev/text/template#hdr-Variables">大元の出典である <code>text/template</code> の公式ドキュメント</a> + </li> + </ul> + </section> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/vhosts/blog/public/posts/atom.xml b/vhosts/blog/public/posts/atom.xml index 5c4a94b4..a8f99d30 100644 --- a/vhosts/blog/public/posts/atom.xml +++ b/vhosts/blog/public/posts/atom.xml @@ -7,7 +7,15 @@ <author> <name>nsfisis</name> </author> - <updated>2024-07-19T00:00:00+09:00</updated> + <updated>2024-08-19T00:00:00+09:00</updated> + <entry> + <id>urn:uuid:eed112e4-3227-4b3f-9991-7e11c288ee2b</id> + <link rel="alternate" href="https://blog.nsfisis.dev/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/"></link> + <title>【Go】 text/template の with や range の内側から外側の "." にアクセスする</title> + <summary>Go言語の text/template における with や range は "." を上書きする。これらの内側から外側の "." にアクセスする方法を調べた。</summary> + <published>2024-08-19T00:00:00+09:00</published> + <updated>2024-08-19T00:00:00+09:00</updated> + </entry> <entry> <id>urn:uuid:222488dd-cf07-4961-83aa-a014b05369ff</id> <link rel="alternate" href="https://blog.nsfisis.dev/posts/2024-07-19/reparojson-fix-only-json-formatter/"></link> diff --git a/vhosts/blog/public/posts/index.html b/vhosts/blog/public/posts/index.html index 4a64804b..10069c06 100644 --- a/vhosts/blog/public/posts/index.html +++ b/vhosts/blog/public/posts/index.html @@ -43,6 +43,21 @@ <h1>投稿一覧</h1> </header> <article class="post-entry"> + <a href="/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/"> + <header class="entry-header"> + <h2>【Go】 text/template の with や range の内側から外側の "." にアクセスする</h2> + </header> + <section class="entry-content"> + <p> + Go言語の text/template における with や range は "." を上書きする。これらの内側から外側の "." にアクセスする方法を調べた。 + </p> + </section> + <footer class="entry-footer"> + <time datetime="2024-08-19">2024-08-19</time> 投稿 + </footer> + </a> + </article> + <article class="post-entry"> <a href="/posts/2024-07-19/reparojson-fix-only-json-formatter/"> <header class="entry-header"> <h2>reparojson: 文法エラーを直すだけの JSON フォーマッタを作った</h2> |
