天天看點

go 模闆詳說

模闆是我們常用的手段用于動态生成頁面,或者用于代碼生成器的編寫等。比如把資料庫的表映射成

go

語言的

struct

,這些體力活,寫個代碼生成器是最合适不過的了.

示例例把表轉成 struct :

go 模闆詳說
當然這篇文章不是寫關于代碼生成器的,是詳細說一下

go

Template

,對

Template

的操作熟悉了後,就可以利用他實作你想要的一些功能。

渲染對象

{{.}}

來渲染對象本身,對象内部的字段可以

{{.field}}

比如下面,我是用一個

map

來存儲的資料,通路key:

name

,并使用

{{.}}

來把

map

列印出來

eg:

tmpl, err := template.New("test").Parse(`hello {{.name}}!
    obj: {{.}}`)
    if err != nil {
        panic(err)
    }
    err = tmpl.Execute(os.Stdout, map[string]interface{}{
        "name": "world", "age": 18})
    if err != nil {
        panic(err)
    }           

輸出

hello world!
obj: map[age:18 name:world]           

結構體内的字段也是用

{{.field}}

tmpl, err := template.New("test").Parse(`hello {{.Name}}!
    obj: {{.}}`)
    if err != nil {
        panic(err)
    }
    err = tmpl.Execute(os.Stdout, struct {
        Name string
        Age  int
    }{Name: "li", Age: 18})
    if err != nil {
        panic(err)
    }           

空格

{{}}

内添加

-

可以去掉空格

  • {{- }}

    去掉左邊所有的空格
  • {{ -}}

    去掉右邊所有的空格
  • {{- -}}

    去掉兩邊所有的空格

    eg:

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
        Age  int
    }{Name: "li", Age: 18})
    if err != nil {
        panic(err)
    }           
  • hello:

    後面的空格到

    {{- .Name}}

    之間的空格會被去掉.
  • {{.Age -}}

    !!!

    之間的空格會被去掉
  • obj:

    {{- . -}}

    end.

    之間的空格都會被去掉。
hello:li
age: 18!!!
obj:{li 18}end.           

自定義變量

除了可以直接使用

go

的對象,也可以直接在模闆中定義變量

{{ $var := }}

,變量定義後,可以在模闆内其他任意地方使用:

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)
    }           
hello li           

方法

方法可以分為全局方法和結構體方法還有内置方法,内置方法也是全局方法的一種

全局方法

template.FuncMap

是一個

map

裡面的

value

必需是方法,傳入的值的參數沒有限制

type FuncMap map[string]interface{}           

比如:定義一個

ReplaceAll

方法,替換所有的指定字元串

例子中把所有的

zhang

替換成

li

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
        Age  int
    }{Name: "zhang_san zhang_si", Age: 18})
    if err != nil {
        panic(err)
    }           
func replace:  li_san li_si           

内置方法

模闆有一些

比如

call

printf

等,和全局方法一樣,直接調用就行

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
        Age  int
    }{Name: "li", Age: 18})
    if err != nil {
        panic(err)
    }           
name: li age: 18           

行為

常用的行為有

if

range

template

if

判斷

{{if }} {{end}}

,可以用于

字元串

bool

或者

數值類型

字元串有資料

bool

值為

true

數值類型

大于

時為真

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)
    }           

輸出:

name:  
      string .Name false 
    desc: xyz
      string .Desc true 
    age: 18
      number .Age true 
    isAdmin: true
      bool .IsAdmin true           

range

range

用于遍例數組,和

go

range

一樣,可以直接得到每個變量,或者得到

index

value

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, map[string]interface{}{
        "val": []string{"a", "b", "c", "d"}})
    if err != nil {
        panic(err)
    }           
a  b  c  d 
id: 0: a  id: 1: b  id: 2: c  id: 3: d           

内嵌template

除了可以在自定義對象還可以自定義内嵌的模闆

{{define "name"}}

,也可以傳參數

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)
    }           

在調用時

{{template "content" "zhang san"}}

傳遞了參數

zhang san

content:  hello zhang san           

注釋

模闆的注釋:

{{/* comment */}}

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)
    }