tonglin0325的个人主页

go学习笔记——text template

golang可以使用text/template来实现模板生成文本,官方文档:https://pkg.go.dev/text/template

1.变量#

可以在模板中定义变量,然后将这些变量赋值到模板的变量中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import "text/template"

// 定义结构体
type Inventory struct {
Material string
Count uint
}
// 赋值
sweaters := Inventory{"wool", 17}
// 定义模板
tmpl, err := template.New("test").Parse(`
{{.Count}} items are made of {{.Material}}
`)
if err != nil {
panic(err)
}
// 填充模板
err = tmpl.Execute(os.Stdout, sweaters)
if err != nil {
panic(err)
}

输出

1
2
17 items are made of wool

2.if else#

1.判断字符串是否相等#

1
2
3
4
5
6
7
8
9
10
11
{{ if eq .Material "wool" }}
Material is "wool"
{{ else if eq .Material "not wool" }}
Material is not "wool"
{{ end }}
{{ if eq .Count 17 }}
Count is 17
{{ else if eq .Count 10 }}
Count is not 10
{{ end }}

输出

1
2
3
4
Material is "wool"

Count is 17

2.多条件,与或非#

1
2
3
4
{{ if or (eq .Material "not wool") (eq .Count 17) }}
Count is 17
{{ end }}

输出

1
2
Count is 17

3.for循环#

1.遍历数组#

在for循环中使用其他变量的时候,要用

取得index和value,使用和

1
2
3
4
{{range $index, $value := .Ips}}
index: {{$index}}, material: {{$.Material}}, value: {{$value}}
{{end}}

输出

1
2
3
4
index: 0, material: wool, value: 192.168.0.1

index: 1, material: wool, value: 192.168.0.2

2.遍历map#

同样也可以使用for循环遍历map,取得key和value

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
type Inventory struct {
Material string
Count uint
Ips []string
Maps map[string]string
}
sweaters := Inventory{
"wool",
17,
[]string{"192.168.0.1", "192.168.0.2"},
map[string]string{
"key": "hello",
"value": "world",
},
}
tmpl, err := template.New("test").Parse(`
{{range $key, $value := .Maps}}
key: {{$key}}, material: {{$.Material}}, value: {{$value}}
{{end}}
`)
if err != nil {
panic(err)
}
err = tmpl.Execute(os.Stdout, sweaters)
if err != nil {
panic(err)
}

4.函数#

1.len函数#

判断数组的长度是否等于1,其中Ips可以是切片或者map

1
2
3
4
5
6
7
8
{{if eq (len .Ips) 1}}
len=1
{{else if eq (len .Ips) 2}}
len=2
{{else}}
other
{{end}}

2.index函数#

可以使用index函数获得数组特定下标的值

1
2
{{index .Ips 0}}

如果和eq函数一起使用

1
2
3
4
{{if or (eq (index .Ips 0) "192.168.0.1") (eq (index .Ips 1) "192.168.0.2")}}

{{end}}

3.for循环下标从1开始#

参考:golang template(数组循环、在循环内使用外部变量、索引从1开始)

4.自定义函数#

可以自定义函数来自己实现函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package main

import (
"bytes"
"strings"
"text/template"
)

func main() {
type Inventory struct {
Material string
Count uint
Ips []string
Maps map[string]string
}
sweaters := Inventory{
"test1,test2",
17,
[]string{"192.168.0.1", "192.168.0.2"},
map[string]string{
"key": "hello",
"value": "world",
},
}
tmpl := template.New("test")
funcs := template.FuncMap{
"hasSuffix": strings.HasSuffix,
"split": strings.Split,
"containItem": containItem,
"renderTemplate": func(name string, data interface{}) (string, error) {
var buf bytes.Buffer
err := tmpl.ExecuteTemplate(&buf, name, data)
return buf.String() + " test", err
},
}
temp, err := tmpl.Funcs(funcs).Parse(
`
{{if hasSuffix .Material "test2"}}
hasSuffix
{{end}}
`)
if err != nil {
panic(err)
}
var output bytes.Buffer
err = temp.Execute(&output, sweaters)
if err != nil {
panic(err)
}
str := output.String()
println(str)
}

func containItem(slice []string, item string) bool {
for _, v := range slice {
if v == item {
return true
}
}
return false
}

判断字符串是否包含特定后缀

1
2
3
4
{{if hasSuffix .Material "test2"}}
hasSuffix
{{end}}

将字符串以特定字符切分成数组,然后遍历

1
2
3
4
5
{{- $items := split .Material "," -}}
{{- range $index, $item := $items -}}
{{$item}}
{{end}}

输出

1
2
3
test1
test2

判断切片是否包含特定字符串

1
2
3
4
{{if containItem .Ips "192.168.0.1"}}
containItem
{{end}}

5.其他#

1.注释#

1
2
{{/* 注释 */}}

2.子模板#

可以在template中使用define关键字定义一个子模板,然后使用template关键字添加这个子模板

1
2
3
4
5
6
7
start define a template
{{- define "T1" -}}
define a template
{{- end -}}
{{template "T1" .}}
end define a template

输出

1
2
3
4
5
6
7
start define a template


define a template

end define a template

3.去除空格#

可以看到上面渲染出来的字符串中有很多的空格,可以使用 - 来去掉多余的空格

比如去掉前面的空格

1
2
{{- "start define a template"}}

去掉后面的空格

1
2
{{"start define a template"}}

去掉模板前后,和模板中的空格

1
2
3
4
5
6
7
{{- "start define a template" -}}
{{define "T1" -}}
define a template
{{- end}}
{{- template "T1" . -}}
{{- "end define a template" -}}

输出

1
2
start define a templatedefine a templateend define a template

4.将子模板定义成一个变量,并使用函数进行处理后输出#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package main

import (
"bytes"
"text/template"
)

func main() {
type Inventory struct {
Material string
Count uint
Ips []string
Maps map[string]string
}
sweaters := Inventory{
"wool",
17,
[]string{"192.168.0.1", "192.168.0.2"},
map[string]string{
"key": "hello",
"value": "world",
},
}
tmpl := template.New("test")
funcs := template.FuncMap{
"renderTemplate": func(name string, data interface{}) (string, error) {
var buf bytes.Buffer
err := tmpl.ExecuteTemplate(&buf, name, data)
return buf.String() + " test", err
},
}
temp, err := tmpl.Funcs(funcs).Parse(
`
{{define "T1" -}}
define a template
{{- end}}

{{define "T111"}}
{{- $message := renderTemplate "T1" . -}}
{{$message}}
{{end}}

{{template "T111" .}}
`)
if err != nil {
panic(err)
}
var output bytes.Buffer
err = temp.Execute(&output, sweaters)
if err != nil {
panic(err)
}
str := output.String()
println(str)
}