go template 简单使用笔记

text/template 包的常用函数说明

func New(name string) *Template
创建一个名为name 的模板

func (t Template) Parse(text string) (Template, error)
将字符串text解析为模板,text里面需要填充的字段要严格按照template包规定的那样填写,如:
fsdnfdsfd{{.Name}}fdsfkksdsdfdfsds{{if .Age}}fgsgdgdf{{else}}fdsfdsfjids{{end}}
Name,Age就是需要被填充的字段

func (t *Template) Execute(wr io.Writer, data interface{}) (err error)
Execute方法将解析好的模板应用到data上,并将输出写入wr。如果执行时出现错误,会停止执行,但有可能已经写入wr部分数据。模板可以安全的并发执行

func Must(t *Template, err error) *Template
模板包里面有一个函数Must,它的作用是检测模板是否正确,例如大括号是否匹配,
注释是否正确的关闭,变量是否正确的书写

func ParseFiles(filenames ...string) (*Template,error)
从文件里读入模板,允许多个文件一起读入

func ParseGlob(pattern string) (Template,error)
当有非常多的文件需要读入的时候该函数可以使用正则表达式读入文件。如:
tp, _ := template.ParseGlob("
.txt")
t, _ := tp.ParseGlob("tp1.txt") //取出指定文件的模板

func (t Template) ExecuteTemplate(wrio.Writer, namestring, data interface{})error
ExecuteTemplate方法类似Execute,但是使用名为name的t关联的模板产生输出。
一般和func ParseGlob(pattern string) (
Template, error)函数一起用,指定使用某个文件模板

func (t *Template) Funcs(funcMapFuncMap) *Template
Funcs方法向模板t的函数字典里加入参数funcMap内的键值对。如果funcMap某个键值对的值不是函数类型或者返回值不符合要求会panic。但是,可以对t函数列表的成员进行重写。方法返回t以便进行链式调用

使用例子

{{.}}的使用

package main
import (
"fmt"
"text/template"
"os"
)
type Person struct {
Count  string
ata  string
}
var data_slice = []string{"hsi", "fribvm","gwoemj"}
var  data_struct = &Person{Count:"dododo", Data:"gdhes"}
var  data_map =map[string]string{"one":"gfsgd", "two":"gdfgdfgs"}

func main() {
str := "I come from china {{.}}"
tp ,err := template.New("tp").Parse(str)
if err != nil {
panic(err)
}

fmt.Println(tp.Execute(os.Stdout,data_slice))
fmt.Println(tp.Execute(os.Stdout,data_struct))
fmt.Println(tp.Execute(os.Stdout,data_map))
}

输出结果

I come from china [hsi fribvm gwoemj]
I come from china {dododo gdhes}
I come from china map[one:gfsgd two:gdfgdfgs]

{{if pipeline}} T1 {{end}}

如果pipeline的值为empty,不产生输出,否则输出T1执行结果

package main
import (
    "fmt"
    "text/template"
    "os"
)
type Person struct {
    Count  string
    Data   string
}
var     data_slice = []string{"hsi", "fribvm","gwoemj"}
var     data_struct = &Person{Count:"dododo", Data:"gdhes"}
var     data_map =map[string]string{"one":"gfsgd", "two":"gdfgdfgs"}

func main() {
    str := `I come from china {{if .}} {{.}}{{end}}`
    tp ,err := template.New("tp").Parse(str)
    if err != nil {
        panic(err)
    }

    fmt.Println(tp.Execute(os.Stdout,data_slice))
    fmt.Println(tp.Execute(os.Stdout,data_struct))
    fmt.Println(tp.Execute(os.Stdout,data_map))
}

这里的T1可以是任意的数据,我这里是用{{.}}来代替,表示如果{{if .}}不为空,就执行T1,为空就不执行。
Empty值包括false、0、任意nil指针或者nil接口,任意长度为0的数组、切片、字典
输出结果:

I come from china  [hsi fribvm gwoemj]
I come from china  {dododo gdhes}
I come from china  map[one:gfsgd two:gdfgdfgs]

{{if pipeline}} T1 {{else}} T0 {{end}}

如果pipeline的值为empty,输出T0执行结果,否则输出T1执行结果

package main
import (
    "fmt"
    "text/template"
    "os"
)
type Person struct {
    Count  string
    Data   string
}
var     data_slice = []string{"hsi", "fribvm","gwoemj"}
var     data_struct = &Person{Count:"dododo", Data:"gdhes"}
var     data_map =map[string]string{"one":"gfsgd", "two":"gdfgdfgs"}

func main() {
    str := `I come from china {{if 0}} {{.}}{{else}}dodododdodo{{end}}`
    tp ,err := template.New("tp").Parse(str)
    if err != nil {
        panic(err)
    }

    fmt.Println(tp.Execute(os.Stdout,data_slice))
    fmt.Println(tp.Execute(os.Stdout,data_struct))
    fmt.Println(tp.Execute(os.Stdout,data_map))
}

输出结果:

I come from china dodododdodo
I come from china dodododdodo
I come from china dodododdodo

{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}

如果pipeline不为empty,执行T1,如果为空,判断else if

package main
import (
    "fmt"
    "text/template"
    "os"
)
type Person struct {
    Count  string
    Data   string
}
var     data_slice = []string{"hsi", "fribvm","gwoemj"}
var     data_struct = &Person{Count:"dododo", Data:"gdhes"}
var     data_map =map[string]string{"one":"gfsgd", "two":"gdfgdfgs"}

func main() {
    str := `I come from china {{if 0}} {{.}}{{else if 1}}dodododdodo{{end}}`
    tp ,err := template.New("tp").Parse(str)
    if err != nil {
        panic(err)
    }

    fmt.Println(tp.Execute(os.Stdout,data_slice))
    fmt.Println(tp.Execute(os.Stdout,data_struct))
    fmt.Println(tp.Execute(os.Stdout,data_map))
}

输出结果:

I come from china  [hsi fribvm gwoemj]
I come from china  {dododo gdhes}
I come from china  map[one:gfsgd two:gdfgdfgs]

{{range pipeline}} T1 {{end}}

pipeline的值必须是数组、切片、字典或者通道。
如果pipeline的值其长度为0,不会有任何输出;
否则dot依次设为数组、切片、字典或者通道的每一个成员元素并执行T1
如果pipeline的值为字典,且键可排序的基本类型,元素也会按键的顺序排序。

package main
import (
    "fmt"
    "text/template"
    "os"
)
type Person struct {
    Count  string
    Data   string
}
var     data_slice = []string{"hsi", "fribvm","gwoemj"}
var     data_struct = &Person{Count:"dododo", Data:"gdhes"}
var     data_map =map[string]string{"one":"gfsgd", "two":"gdfgdfgs"}

func main() {
    str := `I come from china {{range .}}{{.}}{{end}}`
    tp ,err := template.New("tp").Parse(str)
    if err != nil {
        panic(err)
    }
    fmt.Println(tp.Execute(os.Stdout,data_slice))
    fmt.Println(tp.Execute(os.Stdout,data_struct))  //这里出错, 它是struct
    fmt.Println(tp.Execute(os.Stdout,data_map))
}

输出结果:

I come from china hsifribvmgwoemj
I come from china template: tp:1:26: executing "tp" at <.>: range can't iterate over {dododo gdhes}
I come from china gfsgdgdfgdfgs

{{range pipeline}} T1 {{else}} T0 {{end}}

pipeline的值必须是数组、切片、字典或者通道。
如果pipeline的值其长度为0,不改变dot的值并执行T0;否则会修改dot并执行T1。

package main
import (
    "fmt"
    "text/template"
    "os"
)
type Person struct {
    Count  string
    Data   string
}
var     data_slice = []string{"hsi", "fribvm","gwoemj"}
var     data_struct = &Person{Count:"dododo", Data:"gdhes"}
var     data_map =map[string]string{"one":"gfsgd", "two":"gdfgdfgs"}

func main() {
    str := `I come from china {{range .}}T1T1T1{{else}}T0T0T0{{end}}`
    tp ,err := template.New("tp").Parse(str)
    if err != nil {
        panic(err)
    }
    fmt.Println(tp.Execute(os.Stdout,data_slice))
    // fmt.Println(tp.Execute(os.Stdout,data_struct))
    fmt.Println(tp.Execute(os.Stdout,data_map))

输出结果:

I come from china T1T1T1T1T1T1T1T1T1
I come from china T1T1T1T1T1T1

{{template "name"}} 和 {{define "T1"}}T1{{end}}

{{template "name"}} 执行名为name的模板,提供给模板的参数为nil,如模板不存在输出为""
{{define "name"}模板内容{{end}}}定义一个名为name的模板
首先创建两个模板文件layout.txt, index.txt,里面的内容如下:
layout.txt:

{{define "layout"}} //定义模板的名称为layout
I am layout
{{.}}

{{template "index"}}    //导入index模板
{{end}}

index.txt:

{{define "index"}}
I am Index
{{end}}

代码:

package main
import (
    "fmt"
    "text/template"
    "os"
)
var     data_slice = []string{"hsi", "fribvm","gwoemj"}
func main() {

    tp, err := template.ParseFiles("layout.txt","index.txt")   //从文件中读入两个模板
    if err != nil{
        panic(err)
    }
    fmt.Println(tp.ExecuteTemplate(os.Stdout,"layout",data_slice))  //执行layout模板
}

输出结果:

I am layout
[hsi fribvm gwoemj]

I am Index

{{template "name" pipeline}}和 {{define "T1"}}T1{{end}}

{{template "name" pipeline}}执行名为name的模板,提供给模板的参数为pipeline的值。
修改layout.txt的内容:

{{define "layout"}} //定义模板的名称为layout
I am layout
{{.}}

{{template "index" .}}    //导入index模板,给index模板传值
{{end}}

修改index的内容;

{{define "index"}}
I am Index
{{.}}  //新加的内容
{{end}}

代码不变。
输出结果:

I am layout
[hsi fribvm gwoemj]

I am Index
[hsi fribvm gwoemj]   //index.txt里的{{.}}被替换了

{{with pipeline}} T1 {{end}}

如果pipeline为empty不产生输出,否则将dot设为pipeline的值并执行T1。不修改外面的dot。
代码:

package main
import (
    "fmt"
    "text/template"
    "os"
)
type Person struct {
    Count  string
    Data   string
}

var     data_slice = []string{"hsi", "fribvm","gwoemj"}
var     data_struct = &Person{Count:"dododo", Data:"gdhes"}
var     data_map =map[string]string{"one":"gfsgd", "two":"gdfgdfgs"}

func main() {

    str := `{{with .}}{{.}}{{end}}`
    tp, err := template.New("tp").Parse(str)
    if err != nil{
        panic(err)
    }
    fmt.Println(tp.Execute(os.Stdout,data_slice))
    fmt.Println(tp.Execute(os.Stdout,data_struct))
    fmt.Println(tp.Execute(os.Stdout,data_map))
}

输出结果:

[hsi fribvm gwoemj]
{dododo gdhes}
map[one:gfsgd two:gdfgdfgs]

{{with pipeline}} T1 {{else}} T0 {{end}}

如果pipeline为empty,不改变dot并执行T0,否则dot设为pipeline的值并执行T1。
代码:

package main
import (
    "fmt"
    "text/template"
    "os"
)
type Person struct {
    Count  string
    Data   string
}

var     data_slice = []string{"hsi", "fribvm","gwoemj"}
var     data_struct = &Person{Count:"dododo", Data:"gdhes"}
var     data_map =map[string]string{"one":"gfsgd", "two":"gdfgdfgs"}

func main() {

    str := `{{with 0}}{{.}}{{else}}T0T0T0{{end}}`
    tp, err := template.New("tp").Parse(str)
    if err != nil{
        panic(err)
    }
    fmt.Println(tp.Execute(os.Stdout,data_slice))
    fmt.Println(tp.Execute(os.Stdout,data_struct))
    fmt.Println(tp.Execute(os.Stdout,data_map))
}

输出结果:

T0T0T0
T0T0T0
T0T0T0

{{if pipeline}} T1 {{end}} 和{{with pipeline}} T1 {{end}}的区别

{{with pipeline}} T1 {{end}}代码:

package main
import (
    "fmt"
    "text/template"
    "os"
)
type Person struct {
    Count  string
    Data   string
}
var     data_map =map[string]string{"one":"gfsgd", "two":"gdfgdfgs"}
func main() {

    str := `{{with .one}}{{.}}{{end}}`    //只输出键one的值
    tp, err := template.New("tp").Parse(str)
    if err != nil{
        panic(err)
    }
    fmt.Println(tp.Execute(os.Stdout,data_map))
}

输出结果:

gfsgd

{{if pipeline}} T1 {{end}}代码:

package main
import (
    "fmt"
    "text/template"
    "os"
)
type Person struct {
    Count  string
    Data   string
}
var     data_map =map[string]string{"one":"gfsgd", "two":"gdfgdfgs"}

func main() {
    str := `{{if .one}}{{.}}{{end}}`   //输出整个map的值
    tp, err := template.New("tp").Parse(str)
    if err != nil{
        panic(err)
    }
    fmt.Println(tp.Execute(os.Stdout,data_map))
}

输出结果:

map[one:gfsgd two:gdfgdfgs]

函数

执行模板时,函数从两个函数字典中查找:首先是模板函数字典,然后是全局函数字典。一般不在模板内定义函数,而是使用Funcs方法添加函数到模板里。方法必须有一到两个返回值,如果是两个,那么第二个一定是error接口类型

模版内定义函数

package main 
import(
    "os"
    "text/template"
)
type MyMethod struct{
    Name string
}

func (my *MyMethod)SayHello() string{//没参数
    return "hello world"
}

func (my *MyMethod)SayYouName(name string) string { //有参数
    return "my name is : " + name
}

func main() {
    mine := &MyMethod{ Name : "boss"}
    tmpl, err := template.New("test").Parse("{{.SayHello}}\n{{.SayYouName .Name}}\n")
    if err != nil { 
        panic(err) 
    }
    err = tmpl.Execute(os.Stdout, mine)
    if err != nil { 
        panic(err)
    }
}

输出结果:

hello world
my name is : boss

使用Funcs方法添加函数到模板

FuncMap类型定义了函数名字符串到函数的映射,每个函数都必须有1到2个返回值,如果有2个则后一个必须是error接口类型;如果有2个返回值的方法返回的error非nil,模板执行会中断并返回给调用者该错误

package main 
import(
    "os"
    "text/template"
)

func SayHello() string{//没参数
    return "hello world"
}

func SayYouName(name string) string { //有参数
    return "my name is : " + name
}

func main() {
    funcMap := template.FuncMap{
        //在FuncMap中声明相应要使用的函数,然后就能够在template字符串中使用该函数
        "SayHello" : SayHello,
        "SayYouName" : SayYouName,
    }
    name := "boss"
    tmpl, err := template.New("test").Funcs(funcMap).Parse("{{SayHello}}\n{{SayYouName .}}\n")
    if err != nil { 
        panic(err) 
    }
    err = tmpl.Execute(os.Stdout, name)
    if err != nil { 
        panic(err)
    }
}

输出结果:

hello world
my name is : boss

下面是定义为函数的二元比较运算的集合:

eq 如果arg1 == arg2则返回真
ne 如果arg1 != arg2则返回真
lt 如果arg1 < arg2则返回真
le 如果arg1 <= arg2则返回真
gt 如果arg1 > arg2则返回真
ge 如果arg1 >= arg2则返回真
使用例子:

package main
import (
    "fmt"
    "text/template"
    "os"
)
type Person struct {
    Count  string
    Data   string
}
var     data_slice = []string{"hsi", "fribvm","gwoemj"}

func main() {

    str := `{{range $in, $v := .}}{{if gt $in 0}}{{$v}}{{end}}{{end}}`   //表示输出下标大于0 的数据
    tp, err := template.New("tp").Parse(str)
    if err != nil{
        panic(err)
    }
    fmt.Println(tp.Execute(os.Stdout,data_slice))
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容