revel 模板无法访问 go 结构体中的未导出(小写首字母)字段;要将嵌套结构体中的切片传递至模板,必须将外层结构体中对应字段名首字母大写,使其成为导出字段,否则会触发“unexported field”运行时错误。
revel 模板无法访问 go 结构体中的未导出(小写首字母)字段;要将嵌套结构体中的切片传递至模板,必须将外层结构体中对应字段名首字母大写,使其成为导出字段,否则会触发“unexported field”运行时错误。
在 Go 中,只有首字母大写的字段才是导出字段(exported),才能被外部包(包括 Revel 的模板引擎)反射访问。你原代码中定义的 alldata 结构体包含未导出字段 company []company(小写 c),导致模板执行时无法解析 .data.company,从而报错:
7: executing "App/Index.html" at <.data.company>: company is an unexported field of struct type interface {}</.data.company>
✅ 正确做法是将字段名改为 Company(首字母大写),同时建议将内嵌的 company 类型也导出(即改名为 Company),以保持命名一致性与可维护性:
// ✅ 正确:所有需在模板中访问的字段必须导出(首字母大写)
type Company struct {
Tradetotals float64
Totals float64
CostCount string
TraderCount string
}
type AllData struct {
Company []Company // 注意:首字母大写,导出字段
}
控制器中使用示例:
func (c App) Index() revel.Result {
data := AllData{
Company: []Company{
{Tradetotals: 123.45, Totals: 987.65, CostCount: "12", TraderCount: "5"},
{Tradetotals: 234.56, Totals: 876.54, CostCount: "8", TraderCount: "3"},
},
}
return c.Render(data)
}
模板(App/Index.html)中即可安全遍历:
{{range $index, $comp := .Company}}
<div>
<button type="submit" class="btn btn-sq-lg btn-danger">
<i class="fa fa-user fa-5x"></i><br>
Demo Danger Button
</button>
<button type="submit" class="btn btn-sq-lg btn-success">
<i class="fa fa-user fa-5x"></i><br>
US: {{$comp.Tradetotals}}<br>
Total: {{$comp.Totals}}<br>
Cost: {{$comp.CostCount}} | Traders: {{$comp.TraderCount}}
</button>
</div>
{{end}}
⚠️ 注意事项:
- Go 模板不区分大小写敏感的字段名匹配,但严格依赖导出性(exportedness)——仅导出字段可见;
- 若结构体定义在其他包中,还需确保该类型本身也是导出的(如 Company 而非 company);
- Revel 默认将传入 c.Render() 的数据绑定到模板的 .(当前上下文),因此无需 .data.company,直接用 .Company 即可(除非你显式包裹在 data 字段中);
- 若坚持使用 .data.Company,则需确保 data 是导出字段,且 AllData 实例作为 data 字段值传入(如 c.Render(map[string]interface{}{"data": data})),但更推荐直接传结构体并简化模板路径。
总结:导出即可见,命名即契约。只要确保结构体字段首字母大写、类型名导出、模板路径与字段名严格一致,嵌套切片就能无缝渲染。











