给定一个结构集合,如何使用“范围”模板迭代器打印出一个表,该表为每个结构分配一行,每个字段的列没有明确指定字段?
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>