GoLang 模板使用简介

2018-01-09 language golang

在前后端分离的时代,模板语言使用的已经很少了,不过很多特定的场景还是很有用的,这里介绍其基本使用方法。

简介

与大多数语言一样,使用 {{}} 来做标识,其包裹的可以是表达式或者变量,如下是一个简单的示例。

package main

import (
	"os"
	"text/template"
)

type Friend struct {
	Name string
}
type Person struct {
	Name    string
	Emails  []string
	Friends []*Friend
}

func main() {
	tpl := `Hello {{ .Name }}!
Emails:
{{- range .Emails }}
    {{ . }}
{{- end }}
Friends:
{{- with .Friends -}}
    {{ range . }}
        {{ .Name -}}
    {{ end }}
{{ end }}`
	t := template.New("test")
	t = template.Must(t.Parse(tpl))
    p := &Person{
		Name:   "andy",
		Emails: []string{"hello@example.com", "world@gexample.com"},
		Friends: []*Friend{{
			Name: "andy",
		}, {
			Name: "andy",
		}},
	}
	t.Execute(os.Stdout, p)
}

渲染后输出如下内容。

Hello andy!
Emails:
    hello@example.com
    world@gexample.com 
Friends:
        andy
        andy

也就是按照 New()Parse()Execute() 顺序分别创建、解析、渲染,其中 {{ . }} 就是 Execute() 中渲染的对象,可以以此引用其中的内容。

作用域

编写模板时会用到 . 点符号,例如 {{ . }}{{ len . }}{{ .Name }}{{ $x.Name }} 等,其代表当前作用域的当前对象。顶层就是 Execute() 函数的入参,如上述示例中的 {{ .Name }} {{ .Emails }} 就相当于 p.Name p.Emails 变量。

而对于 rangewithif 等内置关键字都有自己本地作用域,上述的 {{range .Emails}} ... {{end}} 中内部结构就是迭代时的每个元素,也就是 p.Emails 这个切片中的字符串。

变量

通过 {{ $var := value }} 声明变量,再用 {{ $var = value }} 重新赋值,通过 {{ $var }} 输出,或者通过 {{ $var := or value default }} 设置默认值。

Actions

{{}} 中包裹的内容统称为 Action,分为数据求值和控制结构两种。

注释

通过 {{/* comments */}} 表示,而注释会占用一行,所以,通常会在前或者后加一个 - 符号去除空白字符。

去除空白

在替换的时候是完全按照文本进行的,除了需要评估和替换的地方,所有的分割符、空格、换行等都原样保留,为了模板可以方便查看一般会进行对齐,但实际内容可能不需要换行、空格之类,可以用如下方式去除。

{{ 符号后加上短横线并保留一个或多个空格来去除前面的空白,包括换行符、制表符、空格等,例如 {{- xxx;同理 xxx -}} 去除后面空白。

{{23}} < {{45}}        -> 23 < 45
{{23}} < {{- 45}}      -> 23 <45
{{23 -}} < {{45}}      -> 23< 45
{{23 -}} < {{- 45}}    -> 23<45

文本输出

输出很简单,直接使用 {{ pipeline }} 即可,其中 pipeline 代表的数据会产生与调用 fmt.Print() 类似的输出,例如整型的 3 会转换成字符串 "3" 输出。

条件语句

与编程语言类似,如下是常见的示例。

{{ if pipeline }} ... {{ end }}
{{ if pipeline }} ... {{ else }} ... {{ end }}
{{ if pipeline }} ... {{ else if pipeline }} ... {{ end }}

如果 pipeline 的值为空就不会输出,对应的空值有 false0nil"" 等。

循环语句

// 简单循环
{{ range pipeline }} T1 {{ end }}
// 如果pipeline长度为0则输出else内容
{{ range pipeline }} T1 {{ else }} T0 {{ end }}
// 同时获取容器下标
{{ range $index, $value := pipeline }} T1 {{ end }}

循环的变量必须是可以迭代的类型值,例如数组、切片、字典、管道等。

模板使用

通过 {{ define "name" }} T {{ end }} 定义一个模板,再用 {{ template "name" }} 引用模板。

还有就是 {{ block "name" pipeline }} T1 {{ end }},增加了一层判断,如果存在名称为 name 的模板就引用,否则就执行自定义的内容。

Pipeline

和 Unix 中管道类似,用来连接多个命令,前面命令将计算结果传递给后个命令的最后位置,如下都输出 output 字符串。

{{`"output"`}}
{{printf "%q" "output"}}
{{"output" | printf "%q"}}
{{printf "%q" (print "out" "put")}}
{{"put" | printf "%s%s" "out" | printf "%q"}}
{{"output" | printf "%s" | printf "%q"}}

with

如下的 with 会创建一个新的上下文环境,在此环境中的 . 与外面的 . 无关。

{{ with pipeline }} T1 {{ end }}
// 如果 pipeline 是空值则输出 T0
{{ with pipeline }} T1 {{ else }} T0 {{ end }}

{{ with arg }}
    . // 此时 . 就是 arg
{{ end }}

函数

比较

包括了 eqneltlegtge 等几个函数,使用方式类似 {{ if (ge .Usage .Limit) }} 这种方式。

index

返回 index 后面的第一个参数的某个索引对应的元素值,例如 {{index x 1}} 表示 x[1],其中 x 必须是一个 mapslicearray

参考