热烈欢迎你,相识是一种缘分,Echa 哥为了你的到来特意准备了一份惊喜,go学习资料《「转」go 语言实战笔记教程系列大纲汇总-值得收藏》
概述
模板引擎是 Web 编程中必不可少的一个组件。模板能分离逻辑和数据,使得逻辑简洁清晰,并且模板可复用。引用第二篇文章《Go Web 编程之 程序结构》一文中的图示,我们可以看到模板引擎在 Web 程序结构中的位置:

模板引擎按照功能可以划分为两种类型:
- 无逻辑模板引擎:此类模板引擎只进行字符串的替换,无其它逻辑;
- 嵌入逻辑模板引擎:此类模板引擎可以在模板中嵌入逻辑,实现流程控制/循环等。
这两类模板引擎都比较极端。无逻辑模板引擎需要在处理器中额外添加很多逻辑用于生成替换的文本。而嵌入逻辑模板引擎则在模板中混入了大量逻辑,导致维护性较差。实用的模板引擎一般介于这两者之间。
在Go 语言中,text/template和html/template两个库实现模板功能。
模板内容可以是 UTF-8 编码的任何内容。其中用{ {和}}包围的部分称为动作,{ {}}外的其它文本在输出保持不变。模板需要应用到数据,模板中的动作会根据数据生成响应的内容来替换。
模板解析之后可以多次执行,也可以并行执行,但是注意使用同一个Writer会导致输出交替出现。
模板的内容较多,我将分为两篇文章介绍。本文介绍text/template,包括 Go 模板的基本概念,用法和注意点。下篇文章介绍html/template。
初体验
使用模板引擎一般有 3 个步骤:
- 定义模板(直接使用字符串字面量或文件);
- 解析模板(使用text/template或html/template中的方法解析);
- 传入数据生成输出。
package mainimport ("log""os""text/template")type User struct {Name stringAge int}func stringLiteralTemplate() {s := "My name is {
{ .Name }}. I am {
{ .Age }} years old."t, err := template.New("test").Parse(s)if err != nil {log.Fatal("Parse string literal template error:", err)}u := User{Name: "darjun", Age: 28}err = t.Execute(os.Stdout, u)if err != nil {log.Fatal("Execute string literal template error:", err)}}func fileTemplate() {t, err := template.ParseFiles("test")if err != nil {log.Fatal("Parse file template error:", err)}u := User{Name: "dj", Age: 18}err = t.Execute(os.Stdout, u)if err != nil {log.Fatal("Execute file template error:", err)}}func main() {stringLiteralTemplate()fileTemplate()}复制代码
在可执行程序目录中新建模板文件test,并写入下面的内容:
My name is {
{ .Name }}. I am {
{ .Age }} years old.复制代码
首先调用template.New创建一个模板,参数为模板名。
然后调用Template类型的Parse方法,解析模板字符串,生成模板主体。这个方法返回两个值。如果模板语法正确,则返回模板对象本身和一个 nil 值。 如果有语法错误,则返回一个 error 类型的值作为第二个返回值,这时不应该使用第一个返回值。
最后,调用模板对象的Execute方法,传入参数。Execute执行模板中的动作,将结果输出到os.Stdout,即标准输出。最终我们看到模板中{ { .Name }}被u的Name字段替换,{ { .Age }}被u的Age字段替换,标准输出中显示下面一行字符串:
My name is darjun. I am 28 years old.复制代码
上面代码中,fileTemplate函数还演示了如何从文件中加载模板。其中template.ParseFiles方法会创建一个模板,并将用户指定的模板文件名用作这个新模板的名字:
t, err := template.ParseFiles("test")复制代码
相当于:
t := template.New("test")t, err := t.ParseFiles("test")复制代码
动作
Go 模板中的动作就是一些嵌入在模板里面的命令。动作大体上可以分为以下几种类型:
- 点动作;
- 条件动作;
- 迭代动作;
- 设置动作;
- 包含动作。
点动作
在介绍其它的动作之前,我们先看一个很重要的动作,点动作({ { . }})。它其实代表是传递给模板的数据,其他动作或函数基本上都是对这个数据进行处理,以此来达到格式化和内容展示的目的。
对前面的代码示例稍作修改:
func main() {s := "The user is {
{ . }}."t, err := template.New("test").Parse(s)if err != nil {log.Fatal("Parse error:", err)}u := User{Name: "darjun", Age: 28}err = t.Execute(os.Stdout, u)if err != nil {log.Fatal("Execute error:", err)}}复制代码
运行程序,标准输出显示:
The user is {darjun 28}.复制代码
实际上,{ { . }}会被替换为传给给模板的数据的字符串表示。这个字符串与以数据为参数调用fmt.Sprint函数得到的内容相同。我们可以为User结构编写一个方法:
func (u User) String() string {return fmt.Sprintf("(name:%s age:%d)", u.Name, u.Age)}复制代码
这样替换的字符串就是格式化之后的内容了:
The user is (name:darjun age:28).复制代码
注意:为了使用的方便和灵活,在模板中不同的上下文内ÿ