Go库text与template包使用示例详解
作者:小马别过河 发布时间:2024-04-26 17:21:16
场景
现在的项目,基本都是前后端分离,后端只要提供Json等格式的数据就行。在这个背景下,模板渲染这个功能备受冷落,很少会在项目中用到。
虽然在 http 服务中,模板解析不常用,但日常开发中,巧妙利用模板生成代码,能使我们开发事半功倍。比如:
使用模板初始化项目。比如我们每次新建一个 http 服务,可能都需要 promethue 监控、日志等模块。每次都实现一遍不现实,(或者 copy 别的项目),我们可以写好模板,支持自定义项目名,初始化新项目。
生成代码。比如之前文章提到的 mockery,就是解析 interface 的语法树,利用模板生成 Mock 对象。
text/template 包
基本用法
text/template
提供的接口和html/template
包一样,只不过后者会为 html 格式的输出做转义,避免攻击。
text/template 用法很简单:
func main() {
// 要注入的变量
type Inventory struct {
Material string
Count uint
}
sweaters := Inventory{"wool", 17}
// 模板内容, {{.xxx}} 格式的都会被注入的变量替换
text := `{{.Count}} items are made of {{.Material}}`
TestTemplate(text, sweaters)
}
func TestTemplate(text string, data interface{}) {
// 初始化,解析
tmpl, err := template.New("test").Parse(text)
if err != nil {
panic(err)
}
// 输出到 os.Stdout
err = tmpl.Execute(os.Stdout, data)
if err != nil {
panic(err)
}
}
结果输出如下:
17 items are made of wool
其中,Execute
的声明为:
// 第一个参数是输出的接口,第二个参数是要注入的数据
func (t *Template) Execute(wr io.Writer, data interface{}) error
第二个参数 data 是 interface{},类型不限,可以是:
结构体,属性在模板中用 {{.Field}} 表示。
map,value 在模板中用 {{.Key}} 表示。
其他简单类型(int、string等),在模板中用{{.}}表示。
// data 为 map
m := map[string]interface{}{"Material": "wool", "Count": 17}
TestTemplate(`{{.Count}} items are made of {{.Material}}`, m) // 输出:17 items are made of wool
// data 为 int,{{.}} 代表注入的变量
TestTemplate(`{{.}} items`, 17) // 输出:17 items
另外,我们也可以使用 template.Must
来检测返回的 error, 如果 error 不为 nil 则 panic。也就是说下面的代码:
tmpl, err := template.New("test").Parse(text)
if err != nil {
panic(err)
}
等价于:
tmpl := template.Must(template.New("test").Parse(txt))
我们重点介绍一下,Parse
的参数(代码中的text
变量),也就是模板的内容。
模板语法
模板里{{xxx}}
格式称之为 Action,默认以{{
和}}
作为分界符,表示模板的流程控制、或者变量。
空白字符
如果 Action 以 {{-
开头,会把 action 左边的空白字符删除,这里的空白字符包括空格、换行、tab等。同理,-}}
会把右边的空白字符删除。如:
d := struct{ Name string }{"Neil"}
TestTemplate(`name = {{.Name}} ;`, d) // 输出:name = Neil ;
// 删除掉 .Name 左边的空格
TestTemplate(`name = {{- .Name}} ;`, d) // 输出:name =Neil ;
// 删除掉 .Name 右边的空格
TestTemplate(`name = {{.Name -}} ;`, d) // 输出:name = Neil;
// 删除掉 .Name 两边的空格
TestTemplate(`name = {{- .Name -}} ;`, d) // 输出:name =Neil;
常用 Action
备注,格式为 {{/*xxxx*/}}
,注意备注的内容是可以换行的。
text := `{{/*this is a comment*/}} name : {{.}} `
TestTemplate(text, "Neil")
// 输出:
// name : Neil
遍历,可以使用 range 关键字。遍历的变量只能是 slice、array、map 或者 channel。
下面代码中的 {{.}}
代表 .MapContent
的元素。
d1 := struct{ MapContent []string }{MapContent: []string{"neil", "garmen", "ray"}}
text = "{{range .MapContent}}{{.}} {{end}}"
TestTemplate(text, d1)
// 输出:
// neil garmen ray
注意,这时候的.
不是代表d1
变量,如果希望在 range 块里面使用d1
, 需要使用 {{$.}}
。
另外也可以使用自定义变量来遍历:
text = "{{range $i,$v := .MapContent}}{{$i}}=>{{$v}} {{end}}"
TestTemplate(text, d1)
// 输出
// 0=>neil 1=>garmen 2=>ray
if-else,变量为零值,或者空 slice、array、map,就相当于是 false。
text = `{{if .Name}}emtpy{{else}}not empty{{end}}`
d = struct{ Name string }{"Neil"}
TestTemplate(text, d) // 输出: empty
if 还可以配合 and、or、not 使用:
// .condition1 && .condition2
if and .condition1 .condition2
// .condition1 || .condition2
if or .condition1 .condition2
// !.condition
if not .condition
with-else, 和if基本一样。区别是,with 作用域的 {{.}}
代表 with 参数,而不是全局的 {{.}}
.
text = "{{with .Name}}{{.}}{{else}}empty{{end}}"
d = struct{ Name string }{"Neil"}
TestTemplate(text, d) // 输出: Neil
自定义模板,使用 define
定义,template
引用。
text = `{{define "T1"}}ONE{{end}}
{{define "T2"}}TWO{{end}}
{{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}}
{{template "T3"}}`
TestTemplate(text, nil)
// 输出: ONE TWO
函数
模板提供了一些函数,如上文的and
、or
、not
。比如下文的 index 函数,打印 MapContent 的 index 为 1 的元素。
text = `{{index .MapContent 1}}`
d1 = struct{ MapContent []string }{MapContent: []string{"neil", "garmen", "ray"}}
TestTemplate(text, d1)
// 输出:garmen
另外,函数还能以管道的方式,一个函数的结果,作为另一个参数的输入,如 {{func1 args | func2 }}
。还有可以使用自定义函数,详情可以查看官方文档:pkg.go.dev/text/templa…。
来源:https://juejin.cn/post/7174364757435088933
猜你喜欢
- 首先说明一下SQL Server内存占用由哪几部分组成。SQL Server占用的内存主要由三部分组成:数据缓存(Data Buffer)、
- 子节点部分选中时父节点也选中如果需求是:选中任何一个子节点都默认选择父节点,怎么办?其实,element-ui也提供了方案,常规下,如果子节
- 一、前言数据库的数据量达到一定程度之后,为避免带来系统性能上的瓶颈。需要进行数据的处理,采用的手段是分区、分片、分库、分表。二、分片(类似分
- 做一个简单WPF连接数据库的控件类型和名称:DataGrid:dataGrid &
- 1、看机器配置,指三大件:cpu、内存、硬盘2、看mysql配置参数3、查系mysql行状态,可以用mysqlreport工具来查看4、查看
- 本文实例讲述了php获取客户端IP及URL的方法。分享给大家供大家参考,具体如下:function getonlineip(){//获取用户
- vue.js在生成相关js和css文件的时候,名称是通过HASH的方式进行生成的,但是每次生成的文件基本都是一样的,那么浏览器就会缓存这些文
- 一、clear(清空字典内容)stu = { 'num1':'Tom', '
- 本文实例讲述了python查看FTP是否能连接成功的方法。分享给大家供大家参考。具体如下:#!/usr/local/bin/python#-
- 本文为大家分享了python实现俄罗斯方块游戏,继上一篇的改进版,供大家参考,具体内容如下1.加了方块预览部分2.加了开始按钮在公司实习抽空
- <?php /* *@author 夜无眠  
- 先上代码举例说明:import argparse parser = argparse.ArgumentParser()
- 前言在制作论文插图时,有时要求将图片的局部放大来展示细节内容,同时将放大图拼接在原图上以方便观察对比。当然直接利用电脑自带的画图软件或者别的
- re.findall()在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。语法格式:re.find
- 有的时候需要手里的音频文件变速听,或可能变慢或可能变快这里使用的python进行操作,我的目标是将文件转成2倍速首先需要安装插件pip in
- 本文介绍我使用QQ得到服务器上回传的python代码的探索历程,面向的对象是对计算机网络有一定了解的读者。期待有兴趣的人和我一起探讨!需求来
- Python SSH远程连接与文件传输from paramiko import (SSHClient, SFTPClient, AutoAd
- 一:分组函数的语句顺序 1 SELECT ... 2 FROM ...
- SQL Server在删除数据后,会重新利用这部分空间,所以如果不是空间紧张的情况下,可以不回收。回收一般先回收日志文件,因为这个回收速度非
- 如何获取一个网站的相关信息,获取赶集网的招聘信息,本文为大家介绍利用python获取赶集网招聘信息的关键代码,供大家参考,具体内容如下imp