go 模板详说

HamletKent 发布于26天前

模板是我们常用的手段用于动态生成页面,或者用于代码生成器的编写等。比如把数据库的表映射成 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 或者 数值类型 大于 0 时为真

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

查看原文: go 模板详说

  • redswan
  • ☞孤身成王彡