遍历map列表的Golang模板遇到的问题及解决方式

出现了什么问题?

今天在使用 go template 渲染文本的时候,在运行的时候,遇到了一个问题导致渲染不成功,具体的问题是:

1
	2021/09/10 09:47:05 template: test:2:3: executing "test" at <.Attributes>: can't evaluate field Attributes in type interface {}

具体的代码如下:

 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
package main

import (
	"log"
	"os"
	"strings"
	"text/template"
)

type TestData struct {
	Name       string `json:"name"`
	Attributes map[string]interface{}
}

const testTemplate = `{{ range $key, $value := .Attributes }}
	{{.Name}} {{ $key }}: {{ $value }}{{- end }}`

func main() {
	tmpl, err := template.New("test").Parse(strings.TrimSpace(testTemplate))
	if err != nil {
		log.Println(err)
		return
	}
	data := TestData{
		"hello",
		map[string]interface{}{
			"key":   "hello",
			"value": "json",
		},
	}
	err = tmpl.Execute(os.Stdout, data)
	if err != nil {
		log.Println(err)
		return
	}
}

问题出现的原因?

模板在 range循环中会把.设置为当前 Attributes 变量, 在 Attributes 变量中没有 name 这个成员结构, 这就导致模板没有渲染成功。

解决

只要在 {{ .Name}} 中在变量前加个 $ 符号 {{ $.Name}}, $表示传递给模板执行的参数, 不是range循环值, 通过添加符号就可以成功渲染Name。

最终代码:

 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
package main

import (
	"log"
	"os"
	"strings"
	"text/template"
)

type TestData struct {
	Name       string `json:"name"`
	Attributes map[string]interface{}
}

const testTemplate = `{{ range $key, $value := .Attributes }}
	{{ $.Name}} {{ $key }}: {{ $value }}{{- end }}`

func main() {
	tmpl, err := template.New("test").Parse(strings.TrimSpace(testTemplate))
	if err != nil {
		log.Println(err)
		return
	}
	data := TestData{
		"hello",
		map[string]interface{}{
			"key":   "hello",
			"value": "json",
		},
	}
	err = tmpl.Execute(os.Stdout, data)
	if err != nil {
		log.Println(err)
		return
	}
}

运行结果:

1
2
3

	hello key: hello
	hello value: json

参考链接: