Text Template 模板

最近,使用到了 html/templatetext/template 类库,通过使用模板,让项目清爽了不少。Go 的这个类似于和 PHP 的模板引擎,使用起来的话,类似于把大象关进冰箱的流程。第一步,安要求准备模板;第二步,按模板准备好数据;第三步,解析数据到模板。

定义模板

当然不使用模板当然也可以,使用 fmt.Sprintf() 同样可以实现。但应对复杂的数据模板时,fmt.Sprintf() 可能会比较麻烦。比如,我们要准备下面这样的一个模板消息,用于查看每周的值班信息。这种值班通知很常见,多见于一些工作群的群发消息。

| 时间 | 第一值班人 | 第二值班人 |
| :----- | :---- | :---- |
| 20210401 | Lucy   | LiLi |
| 20210402 | Neojos | Tom  |

使用 text/template 实现的过程,定义模板变量如下。代码中使用到了反引号,使用反引号定义字符串会保持字符串的原始格式。模板中的中划线表示清除空格的含义,写好模板非常简单,就是几个正常的模板关键字,比如条件判断:{{ if }} {{ else }} {{ end }}。下面是在模板中循环遍历的模板。

var Template = `
| 时间 | 第一值班人 | 第二值班人 |
| :----- | :---- | :---- |
{{- range . }}
| {{ .Date}}   {{range .Persons}} | @{{.}}   {{end}} |
{{- end -}}`

构造数据

传递给模板的数据可以是数组、切片、map、或者 struct等,只要和模板中的占位解析能一一对应上就可以。按照上面的模板,我们只需要构造一个特定类型的切片结构,包含值班日期和值班人两个信息,其中值班人又区分主备,所以,值班人的类型也是一个切片。

type RowUnit struct {
    Date    string
    Persons []string
}

// 简化值班的数据,假设 rows 里全是数据,其中 RowUnit.Persons 有且只有2个用户名称
rows := []*RowUnit{}

解析模板

代码中解析模板,变量 text 是模板解析后的内容。方法 New 用来创建模板,方法 Execute 用来将数据解析到模板 Execute 的第一个类型是 io.Writer,会将模板解析后的结构写入到这个参数中,所以,最终 text 中会存储数据绑定模板后的信息。

t, err := template.New("duty").Parse(Template)
if err != nil {
	return
}

text := new(bytes.Buffer)
err = t.Execute(text, users)

模板函数

模板使用的过程非常简单,使用的时候,关键就在于多熟悉它的用法,①如何在模板中展示一个字段;②如何使用一些条件判断、循环语句。下面我们来看一下模板函数,简单来说,就是预置的一些函数用法。

拿最常见的就是比较函数来说,我们在上面的例子扩展一下比较的功能,其中 eq 就是内置的模板函数,用来做两个数据的比较。你要是写成 == 的比较方式,编译模板就会报错误信息。从这个例子中,也可以看出模板函数的用法,函数名后面跟参数,参数和参数之间使用空格分割。

| 时间 | 第一值班人 | 第二值班人 |
| :----- | :---- | :---- |
{{- range . }}
	{{ if eq .Date "20210201" }} {{.Date}} {{ end }} {{range .Persons}} | @{{.}} {{end}} |
{{- end -}}`

除了模板函数,我们也可以自定义函数,然后在模板中引用自定义的函数。其实,函数的返回值是一个关键,函数是不是只可以有一个返回值,如果要返回 error 该如何处理,我们可以通过一个例子来看一下。当然,我们先看看如何将自定义函数注册到模板:

下面声明了一个 workStatus 函数,它的功能就是:通过传递的名称来判断当前员工的工作状态。在创建模板的时候调用 Funcs 来传递,主要看 FunMap 的类型,在函数的注释中有详细的介绍,函数可以返回一个返回值,或者函数返回一个返回值和一个 error,其他情况的返回是不允许的。

// FuncMap is the type of the map defining the mapping from names to functions.
// Each function must have either a single return value, or two return values of
// which the second has type error. In that case, if the second (error)
// return value evaluates to non-nil during execution, execution terminates and
// Execute returns that error.

type FuncMap map[string]any
funcMap := template.FuncMap{
		"workStatus": func(name string) string {
			if name == "chen" {
				return "陈(已离职)"
			}
			return name
		},
	}

	t, err := template.New("duty").Funcs(funcMap).Parse(Template)
	if err != nil {
	}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值