Как получить доступ к полю объекта по переменной в шаблоне?

У меня есть вложенный цикл:

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

dataList — это массив модели формы. С полями ID, Title тогда columns будет переменной []string, содержащей имена всех полей модели формы, такие как ID, Title.

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

Я пробовал с {{(index .listData 0).Title}}, и это работает.

Но если я хочу получить доступ к $dx.Title, $dx.ID .... с Title, ID в качестве переменных, но это не работает. Я пробовал $dx[$c].

Можно легко добиться того же с Python

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

person TomSawyer    schedule 02.02.2018    source источник
comment
Я думаю, это хороший вопрос. Важные вещи, чтобы узнать здесь. Почему закрытое голосование?   -  person Shahriar    schedule 02.02.2018
comment
Вы говорите, что $dx.Title не работает, но ваш код этого не делает. Кроме того, как это не работает? Каков был результат? И какова ваша реальная структура данных? Здесь недостаточно информации, чтобы ответить на ваш вопрос. Включите минимальный, полный и проверяемый пример.   -  person Flimzy    schedule 02.02.2018
comment
@Flimzy Это правильный и достаточно информационный вопрос. Что я должен спросить? $dx.Title = $dx.$c, все, что я хочу, это сделать доступ к полю/свойству объекта, как в другом языке.   -  person TomSawyer    schedule 02.02.2018
comment
@TomSawyer, можете ли вы дать нам весь код и структуру данных?   -  person Abu Hanifa    schedule 02.02.2018
comment
@AbuHanifa Код прост, dataList - это массив модели orm. С полями ID, Title вы видите цикл для получения их всех, затем columns - это переменная []string, содержащая все имена полей модели формы, такие как ID, Title   -  person TomSawyer    schedule 02.02.2018
comment
Я думаю, он имеет в виду, что $c повторяет Title ID и так далее.   -  person leaf bebop    schedule 02.02.2018


Ответы (1)


Чтобы получить доступ к значениям полей структуры, заданным их именами, вам потребуется помощь пакета 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, если данное имя поля недопустимо, или возвращать ошибку, которая обрабатывается механизмом шаблонов (в этом случае выполнение шаблона будет прервано из-за возвращаемой вами ошибки).

person icza    schedule 02.02.2018
comment
Спасибо, icza, я думал, что пользовательская функция - единственный шанс :(, шаблон go должен иметь встроенную функцию для этого - person TomSawyer; 02.02.2018