午安 發表於 2020-5-6 11:47:00

go 模板详说

<p>模板是我们常用的手段用于动态生成页面,或者用于代码生成器的编写等。比如把数据库的表映射成<code>go</code>语言的<code>struct</code>,这些体力活,写个代码生成器是最合适不过的了.<br>
示例把表转成 struct :<br>
这里--&gt; go模板-代码生成器</p>
<p><img src="https://img2020.cnblogs.com/blog/342595/202005/342595-20200506114623005-2058622212.png" alt="" loading="lazy"></p>
<p>当然这篇帖子不是写关于代码生成器的,是详细说一下<code>go</code>的<code>Template</code>,对<code>Template</code>的操作熟悉了后,就可以利用他实现你想要的一些功能。</p>
<h2 id="渲染对象">渲染对象</h2>
<p><code>{{.}}</code>来渲染对象本身,对象内部的字段可以<code>{{.field}}</code><br>
比如下面,我是用一个 <code>map</code>来存储的数据,访问key: <code>name</code>,并使用<code>{{.}}</code>来把 <code>map</code>打印出来<br>
eg:</p>
<pre><code>        tmpl, err := template.New("test").Parse(`hello {{.name}}!
        obj: {{.}}`)
        if err != nil {
                panic(err)
        }
        err = tmpl.Execute(os.Stdout, mapinterface{}{
                "name": "world", "age": 18})
        if err != nil {
                panic(err)
        }
</code></pre>
<p>输出</p>
<pre><code>hello world!
obj: map
</code></pre>
<p>结构体内的字段也是用<code>{{.field}}</code></p>
<pre><code>        tmpl, err := template.New("test").Parse(`hello {{.Name}}!
        obj: {{.}}`)
        if err != nil {
                panic(err)
        }
        err = tmpl.Execute(os.Stdout, struct {
                Name string
                Ageint
        }{Name: "li", Age: 18})
        if err != nil {
                panic(err)
        }
</code></pre>
<h3 id="空格">空格</h3>
<p>在<code>{{}}</code>内添加 <code>-</code>可以去掉空格</p>
<ul>
<li><code>{{- }}</code> 去掉左边所有的空格</li>
<li><code>{{ -}}</code> 去掉右边所有的空格</li>
<li><code>{{- -}}</code> 去掉两边所有的空格<br>
<code>eg:</code></li>
</ul>
<pre><code>        tmpl, err := template.New("test").Parse(`hello:    {{- .Name}}
        age: {{.Age -}}   !!!
        obj:   
        {{- . -}}   end.`)
        if err != nil {
                panic(err)
        }
        err = tmpl.Execute(os.Stdout, struct {
                Name string
                Ageint
        }{Name: "li", Age: 18})
        if err != nil {
                panic(err)
        }
</code></pre>
<ul>
<li><code>hello:</code> 后面的空格到<code>{{- .Name}}</code> 之间的空格会被去掉.</li>
<li><code>{{.Age -}}</code>到 <code>!!!</code>之间的空格会被去掉</li>
<li><code>obj:</code>到<code>{{- . -}}</code>到 <code>end.</code>之间的空格都会被去掉。</li>
</ul>
<pre><code>hello:li
age: 18!!!
obj:{li 18}end.
</code></pre>
<h3 id="自定义变量">自定义变量</h3>
<p>除了可以直接使用<code>go</code>的对象,也可以直接在模板中定义变量<code>{{ $var := }}</code>,变量定义后,可以在模板内其他任意地方使用:</p>
<pre><code>        tmpl, err := template.New("test").Parse(`{{$a := "li"}} hello {{$a}}`)
        if err != nil {
                panic(err)
        }
        err = tmpl.Execute(os.Stdout, nil)
        if err != nil {
                panic(err)
        }
</code></pre>
<p>输出</p>
<pre><code>hello li
</code></pre>
<h2 id="方法">方法</h2>
<p>方法可以分为全局方法和结构体方法还有内置方法,内置方法也是全局方法的一种</p>
<h3 id="全局方法">全局方法</h3>
<p><code>template.FuncMap</code> 是一个<code>map</code>里面的<code>value</code>必需是方法,传入的值的参数没有限制</p>
<pre><code>type FuncMap mapinterface{}
</code></pre>
<p>比如:定义一个<code>ReplaceAll</code>方法,替换所有的指定字符串<br>
例子中把所有的<code>zhang</code>替换成<code>li</code></p>
<pre><code>        tmpl, err := template.New("test").Funcs(template.FuncMap{
                "ReplaceAll": func(src string, old, new string) string {
                        return strings.ReplaceAll(src, old, new)
                },
        }).Parse(`func replace:{{ReplaceAll .Name "zhang" "li"}}`)
        if err != nil {
                panic(err)
        }
        err = tmpl.Execute(os.Stdout, struct {
                Name string
                Ageint
        }{Name: "zhang_san zhang_si", Age: 18})
        if err != nil {
                panic(err)
        }
</code></pre>
<p>输出</p>
<pre><code>func replace:li_san li_si
</code></pre>
<h4 id="内置方法">内置方法</h4>
<p>模板有一些内置方法比如 <code>call</code>   <code>printf</code> 等,和全局方法一样,直接调用就行</p>
<pre><code>        tmpl, err := template.New("test").Parse(`{{printf "name: %s age: %d" .Name .Age}}`)
        if err != nil {
                panic(err)
        }
        err = tmpl.Execute(os.Stdout, struct {
                Name string
                Ageint
        }{Name: "li", Age: 18})
        if err != nil {
                panic(err)
        }
</code></pre>
<p>输出</p>
<pre><code>name: li age: 18
</code></pre>
<h2 id="行为">行为</h2>
<p>常用的行为有<code>if</code> <code>range</code> <code>template</code>等</p>
<h3 id="if">if</h3>
<p>判断 <code>{{if }}{{end}}</code>,可以用于<code>字符串</code> <code>bool</code> 或者<code>数值类型</code><br>
当 <code>字符串有数据</code> 或者<code>bool</code>值为<code>true</code> 或者<code>数值类型</code>大于<code>0</code> 时为真</p>
<pre><code>        tmpl, err := template.New("test").Parse(`
        name: {{.Name}}
        {{- if .Name}}
      string .Name true
        {{else}}
      string .Name false
        {{end -}}
        desc: {{.Desc}}
        {{- if .Desc}}
      string .Desc true
        {{else}}
      string .Desc false
        {{end -}}
        age: {{.Age}}
        {{- if .Age}}
      number .Age true
        {{else}}
          number .Age true false
        {{end -}}
        isAdmin: {{.IsAdmin}}
        {{- if .Age}}
      bool .IsAdmin true
        {{else}}
          bool .IsAdmin true false
        {{end}}
        `)
        if err != nil {
                panic(err)
        }
        err = tmpl.Execute(os.Stdout, struct {
                Name    string
                Desc    string
                Age   int
                IsAdmin bool
        }{Name: "", Desc: "xyz", Age: 18, IsAdmin: true})
        if err != nil {
                panic(err)
        }
</code></pre>
<p>输出:</p>
<pre><code>        name:
      string .Name false
        desc: xyz
      string .Desc true
        age: 18
      number .Age true
        isAdmin: true
      bool .IsAdmin true
</code></pre>
<h3 id="range">range</h3>
<p><code>range</code> 用于遍例数组,和<code>go</code>的 <code>range</code>一样,可以直接得到每个变量,或者得到 <code>index</code> 和<code>value</code></p>
<pre><code>        tmpl, err := template.New("test").Parse(`
        {{range .val}} {{.}} {{end}}
        {{range $idx, $value := .val}} id: {{$idx}}: {{$value}} {{end}}`)
        if err != nil {
                panic(err)
        }
        err = tmpl.Execute(os.Stdout, mapinterface{}{
                "val": []string{"a", "b", "c", "d"}})
        if err != nil {
                panic(err)
        }
</code></pre>
<p>输出</p>
<pre><code>abcd
id: 0: aid: 1: bid: 2: cid: 3: d
</code></pre>
<h3 id="内嵌template">内嵌template</h3>
<p>除了可以在自定义对象还可以自定义内嵌的模板<code>{{define "name"}}</code>,也可以传参数</p>
<pre><code>        tmpl, err := template.New("test").Parse(`
        {{define "content"}} hello {{.}} {{end}}
        content: {{template "content" "zhang san"}}`)
        if err != nil {
                panic(err)
        }
        err = tmpl.Execute(os.Stdout, nil)
        if err != nil {
                panic(err)
        }
</code></pre>
<p>在调用时<code>{{template "content" "zhang san"}}</code> 传递了参数 <code>zhang san</code><br>
输出:</p>
<pre><code>content:hello zhang san
</code></pre>
<h3 id="注释">注释</h3>
<p>模板的注释: <code>{{/* comment */}}</code></p>
<pre><code>        tmpl, err := template.New("test").Parse(`
        {{/* 注释 */}}
        {{define "content"}} hello {{.}} {{end}}
        content: {{template "content" "zhang san"}}`)
        if err != nil {
                panic(err)
        }
        err = tmpl.Execute(os.Stdout, nil)
        if err != nil {
                panic(err)
        }
</code></pre>


</div>
<div id="MySignature" role="contentinfo">
    <div id="AllanboltSignature">
<div>作者:李鹏</div>
<div>出处:http://www.cnblogs.com/li-peng/</div>
<div>本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 </div>
</div><br><br>
来源:https://www.cnblogs.com/li-peng/p/12835425.html
頁: [1]
查看完整版本: go 模板详说