Go库text与template包使用示例详解

 更新时间:2022年12月15日 10:17:29   作者:小马别过河  
这篇文章主要为大家介绍了Go库text与template包使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

场景

现在的项目,基本都是前后端分离,后端只要提供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

函数

模板提供了一些函数,如上文的andornot。比如下文的 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…

总结

text/template 功能挺多,本文只是大致介绍一下,详情还得移步官网

以上就是Go库text与template包使用示例详解的详细内容,更多关于Go库text template包的资料请关注脚本之家其它相关文章!

相关文章

  • golang对自定义类型进行排序的解决方法

    golang对自定义类型进行排序的解决方法

    学习一门编程语言,要掌握原子数据类型,还需要掌握自定义数据类型。下面这篇文章主要给大家介绍了关于golang如何对自定义类型进行排序的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下。
    2017-12-12
  • Go语言kafka生产消费消息实例搬砖

    Go语言kafka生产消费消息实例搬砖

    这篇文章主要为大家介绍了Go语言kafka生产消费消息的实例搬砖,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • 大多数Go程序员都走过的坑盘点解析

    大多数Go程序员都走过的坑盘点解析

    这篇文章主要为大家介绍了大多数Go程序员都走过的坑盘点解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • GO语言导入自己写的包(同级目录和不同目录)

    GO语言导入自己写的包(同级目录和不同目录)

    本文介绍了如何在Go语言项目中导入同级目录和不同目录的包,详细解释了创建文件结构、编写主函数、同级目录和不同目录方法的调用,适合初学者参考,帮助理解Go项目的基本构建和包管理
    2024-09-09
  • Go语言实现UDP版聊天小工具的示例详解

    Go语言实现UDP版聊天小工具的示例详解

    这篇文章主要为大家详细介绍了如何利用Go语言实现聊天小工具(UDP版),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • golang 格式化输入输出操作

    golang 格式化输入输出操作

    这篇文章主要介绍了golang 格式化输入输出操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • go将request body绑定到不同的结构体中教程

    go将request body绑定到不同的结构体中教程

    这篇文章主要为大家介绍了go将request body绑定到不同的结构体中教程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • 浅析go逆向符号恢复

    浅析go逆向符号恢复

    这篇文章主要介绍了go逆向符号恢复的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • GoLang context包的使用方法介绍

    GoLang context包的使用方法介绍

    日常Go开发中,Context包是用的最多的一个了,几乎所有函数的第一个参数都是ctx,那么我们为什么要传递Context呢,Context又有哪些用法,底层实现是如何呢?相信你也一定会有探索的欲望,那么就跟着本篇文章,一起来学习吧
    2023-03-03
  • 手把手教你导入Go语言第三方库

    手把手教你导入Go语言第三方库

    本文主要介绍了手把手教你导入Go语言第三方库,通过导入gin包来深入学习,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08

最新评论