Text模板

  Python有f-string,可以实现模板的功能,但go也有fmt包,可以模板化输出。但是fmt包不够强大,所以GoLang提供了两个template包,text和html包,里面包含了更强大的模板输出能力。我以text/template包举个例子:

package main

import (
	"os"
	"text/template"
)

type Pet struct {
	Name    string
	Gender  string
	Species string
	Age     int
}

func main() {

	temp := `名字:{{.Name}}
性别:{{.Gender}}
品种:{{.Species}}
年龄:{{.Age}}岁
`
	t, _ := template.New("temp").Parse(temp)
	dog := Pet{
		Age:     1,
		Gender:  "雄性",
		Species: "兔",
		Name:    "乖",
	}
	t.Execute(os.Stdout, dog)

}

  输出结果如下:

名字:乖  
性别:雄性
品种:兔  
年龄:1岁 
HTML模板

  HTML模板与TEXT模板有很多不同,篇幅有限,我也写不完,只挑一个重要的,就是特殊字符串转义。把上面的例子改一改,加入一些HTML字符:

package main

import (
	"html/template"
	"os"
)

type Pet struct {
	Name    string
	Gender  string
	Species string
	Age     int
}

func main() {

	temp := `名字:{{.Name}}
性别:{{.Gender}}
品种:{{.Species}}
年龄:{{.Age}}岁
`
	t, _ := template.New("temp").Parse(temp)
	dog := Pet{
		Age:     1,
		Gender:  "雄性",
		Species: "兔",
		Name:    "<b>乖</b>",
	}
	t.Execute(os.Stdout, dog)

}

  输出结果中,大于号和小于号都被HTML转义了:

名字:&lt;b&gt;乖&lt;/b&gt;
性别:雄性
品种:兔
年龄:1岁
加载文件

  上面的例子都是简单的模板,但是如果遇到复杂的模板呢?这个时候需要用到template.ParseFiles函数了,首先先建立一个文件,取名为template.ParseFiles,内容如下:

我养了一条小{{.Species}},TA的名字叫做{{.Name}},他是一个小{{.Gender}}生,今年{{.Age}}岁啦。

  然后再GoLang程序中加载这个模板,在将变量传进去,如以下代码:

package main

import (
	"fmt"
	"os"
	"text/template"
)

type Pet struct {
	Name    string
	Gender  string
	Species string
	Age     int
}

func main() {
	t, _ := template.ParseFiles("demo.tpl")
	dog := Pet{
		Age:     1,
		Gender:  "女",
		Species: "兔",
		Name:    "乖",
	}
	err := t.Execute(os.Stdout, dog)
	if err != nil {
		fmt.Println(err)
	}

}

  输出结果:

我养了一条小兔,TA的名字叫做乖,TA是一个小女生,今年1岁啦。
循环

  与Java的Freemarker、velocity等模板一样,go的模板也支持循环。如果不支持循环,是不可能是一个可以使用的模板。因为实际项目中,列表式的数据太多了。GoLang模板的循环很简单,以range开始,以end结束,以下是例子:

package main

import (
	"html/template"
	"os"
)

type Pet struct {
	Name    string
	Gender  string
	Species string
	Age     int
}

func main() {

	temp := `名字:{{.Name}}
性别:{{.Gender}}
品种:{{.Species}}
年龄:{{.Age}}岁
`
	t, _ := template.New("temp").Parse(temp)
	dog := Pet{
		Age:     1,
		Gender:  "雄性",
		Species: "兔",
		Name:    "<b>乖</b>",
	}
	t.Execute(os.Stdout, dog)

}

  上述代码的执行结果符合预期:

------------------
名字:乖
性别:雄性        
品种:兔
年龄:1岁
------------------
名字:Meow        
性别:雌性        
品种:猫
年龄:2岁
------------------
名字:汪汪        
性别:雄性        
品种:犬
年龄:3岁
选择

  虽说选择语法,在模板中不是必须的,因为这又可能会使得业务逻辑转移到模板中。学习过MVC开发思想的我们是不想这样开发的。但是有时候选择语法是必须的,假如说奇数行用红色,偶数行用蓝色,这种需求就必须在模板中使用选择语法了,也就是大家常用的if语句。if语句还要配合关系运算符使用,但是GoLang的关系运算符比较特殊,是先写运算符,再参数的,我以小于等于为例子,讲讲这个特性:

package main

import (
	"fmt"
	"html/template"
	"os"
)

type Pet struct {
	Name    string
	Gender  string
	Species string
	Age     int
}

func main() {

	temp := `{{range .}}------------------
名字:{{.Name}}
性别:{{.Gender}}
品种:{{- if lt .Age 2}}小{{- else}}大{{- end}}{{.Species}}
年龄:{{.Age}}岁
{{end}}
`
	t, _ := template.New("temp").Parse(temp)
	dog := []Pet{
		{
			Age:     1,
			Gender:  "雄性",
			Species: "兔",
			Name:    "乖",
		},
		{
			Age:     2,
			Gender:  "雌性",
			Species: "猫",
			Name:    "Meow",
		},
		{
			Age:     3,
			Gender:  "雄性",
			Species: "狗",
			Name:    "汪汪",
		},
	}
	err := t.Execute(os.Stdout, dog)
	if err != nil {
		fmt.Println(err)
	}
}

  上述代码中判断小于2是用if lt .Age 2这样的语法,而不是if .Age lt 2,有点不符合平常的语法习惯。但造成这种现象的原因其实是go的模板中,lt是一个函数。上述代码执行结果如下:

------------------
名字:乖
性别:雄性        
品种:小兔        
年龄:1岁
------------------
名字:Meow        
性别:雌性        
品种:大猫        
年龄:2岁
------------------
名字:汪汪
性别:雄性
品种:大狗
年龄:3岁