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

出现了什么问题?

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

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

具体的代码如下:

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。

最终代码:

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
 }
}

运行结果:


 hello key: hello
 hello value: json

参考链接