给定一个结构集合,如何使用“范围”模板迭代器打印出一个表,该表为每个结构分配一行,每个字段的列没有明确指定字段?
- container := []Node
- type Node struct {
- Contact_id int
- Employer_id int
- First_name string
- Middle_name string
- Last_name string
- }
模板代码:
- {{range .container}}
- <tr>
- <td>{{.Prefix}}</td>
- <td>{{.First_name}}</td>
- <td>{{.Middle_name}}</td>
- <td>{{.Last_name}}</td>
- <td>{{.Contact_id}}</td>
- <td>{{.Employer_id}}</td>
- </tr>
- {{end}}
当我尝试使用迭代值时
- {{range .container}}
- {{range .}}
- <td>{{.}}</td>
- {{end}}
- {{end}}
我被告知我不能迭代价值观.
有没有干净的方法来做到这一点?
解决方法
使用html / template,您无法遍历结构中的字段.在包装的
documentation中,您可以阅读:
{{range pipeline}} T1 {{end}}
The value of the pipeline must be an array,slice,map,or channel.
也就是说,Pipeline不能是一个struct.要么你需要:
>使用中间类型,例如. [] [] interface {},作为传递给模板的容器变量
>如您所示,分别输入每个单元格
>创建一个模板函数,将结构值转换为可以迭代的某种类型
由于struct是在编译时定义的,并且在运行时不会更改其结构,因此迭代不是必需的,并且不会使模板中的内容更清晰.我会反对它.
编辑
但有时反思是件好事. Brenden还指出,您实际上可以让范围迭代函数返回的值.如果使用反射,这将是最简单的方法.
使用模板函数的完整工作示例:
- package main
- import (
- "html/template"
- "os"
- "reflect"
- )
- type Node struct {
- Contact_id int
- Employer_id int
- First_name string
- Middle_name string
- Last_name string
- }
- var templateFuncs = template.FuncMap{"rangeStruct": RangeStructer}
- // In the template,we use rangeStruct to turn our struct values
- // into a slice we can iterate over
- var htmlTemplate = `{{range .}}<tr>
- {{range rangeStruct .}} <td>{{.}}</td>
- {{end}}</tr>
- {{end}}`
- func main() {
- container := []Node{
- {1,12,"Accipiter","ANisus","Nisus"},{2,42,"Hello","my","World"},}
- // We create the template and register out template function
- t := template.New("t").Funcs(templateFuncs)
- t,err := t.Parse(htmlTemplate)
- if err != nil {
- panic(err)
- }
- err = t.Execute(os.Stdout,container)
- if err != nil {
- panic(err)
- }
- }
- // RangeStructer takes the first argument,which must be a struct,and
- // returns the value of each field in a slice. It will return nil
- // if there are no arguments or first argument is not a struct
- func RangeStructer(args ...interface{}) []interface{} {
- if len(args) == 0 {
- return nil
- }
- v := reflect.ValueOf(args[0])
- if v.Kind() != reflect.Struct {
- return nil
- }
- out := make([]interface{},v.NumField())
- for i := 0; i < v.NumField(); i++ {
- out[i] = v.Field(i).Interface()
- }
- return out
- }
输出:
- <tr>
- <td>1</td>
- <td>12</td>
- <td>Accipiter</td>
- <td>ANisus</td>
- <td>Nisus</td>
- </tr>
- <tr>
- <td>2</td>
- <td>42</td>
- <td>Hello</td>
- <td>my</td>
- <td>World</td>
- </tr>