如何通过模板中的变量访问对象字段?

时间:2018-02-02 09:39:43

标签: go nested field go-templates

我有一个嵌套循环:

{{$columns := .columns}}
{{range $dx := .dataList}}
    {{range $c := $columns}}
        {{index $dx $c}}
    {{end}}
{{end}}

dataList是orm模型数组。对于ID, Title字段,columns []string变量包含所有orm模型字段名称,如ID, Title

type AdFile struct {
    ID      uint `gorm:"primary_key"`
    Title   string
}

我尝试使用{{(index .listData 0).Title}}并且有效。

但是,如果我想访问$dx.Title$dx.ID .... TitleID作为变量,但它不起作用。我试过$dx[$c]

可以轻松地用Python实现同样的目标

for i in list_data
    tr
        for p in columns
            td=i[p]

1 个答案:

答案 0 :(得分:2)

要访问由其名称指定的结构的字段值,您需要reflect包中的帮助。可以这样做:

v := AdFile{ID:1, Title: "T1"} // A struct value
name := "ID"                   // field name

fieldValue := reflect.ValueOf(v).FieldByName(name).Interface()

由于这是Go代码,因此您无法将其嵌入到模板中。但是您可以使用Template.Funcs()方法注册自定义函数,该方法可以从模板中调用。

所以让我们这样做:将此功能包装到一个函数中,并使用名称"Field"注册它,以便我们可以从我们的模板中调用它。

func main() {
    t := template.Must(template.New("").Funcs(template.FuncMap{
        "Field": func(v interface{}, name string) interface{} {
            return reflect.ValueOf(v).FieldByName(name).Interface()
        },
    }).Parse(templ))

    m := map[string]interface{}{
        "columns": []string{"ID", "Title"},
        "dataList": []AdFile{
            {ID: 1, Title: "Title1"},
            {ID: 2, Title: "Title2"},
        },
    }

    if err := t.Execute(os.Stdout, m); err != nil {
        panic(err)
    }

}

const templ = `{{$columns := .columns}}
{{range $dx := .dataList}}
    {{range $c := $columns}}
        {{- Field $dx $c }}
    {{end}}
{{end}}`

上述应用的输出(在Go Playground上尝试):

1
Title1


2
Title2

注意:注册的"Field"函数中省略了错误检查。如果给定的字段名称无效,您可以改进它以返回nil,或者返回由模板引擎处理的错误(在这种情况下,模板执行将因您返回的错误而中止)。