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))
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容