
go模板无法遍历结构体中的切片,通常是因为该字段未导出(首字母小写),导致text/template包忽略该字段;只需将字段名首字母大写并同步更新模板引用即可修复。
在 Go 的 text/template 中,所有被模板访问的字段、方法和变量都必须是导出的(exported)——即名称必须以大写字母开头。这是 Go 反射机制的硬性要求,模板引擎依赖 reflect 包读取数据,而 reflect 无法访问非导出(小写首字母)字段。
在你的示例中,Context 结构体定义为:
type Context struct {
people []Person // ❌ 小写 'p' → 非导出字段 → 模板不可见
}尽管 Person 类型及其字段 Name 和 Senior 均已正确导出,但外层 people 字段不可见,因此 $.people 在模板中求值为 nil 或空值,range 迭代不执行,最终输出为空。
✅ 正确做法是将字段改为导出形式,并同步更新模板表达式:
type Context struct {
People []Person // ✅ 大写 'P' → 导出字段 → 模板可访问
}对应模板需同步修改为:
{{range $i, $x := $.People}} Name={{$x.Name}} Senior={{$x.Senior}} {{end}}完整可运行修正版如下:
package main
import (
"os"
"text/template"
)
type Context struct {
People []Person // ✅ 导出字段
}
type Person struct {
Name string // ✅ 导出
Senior bool // ✅ 导出
}
func main() {
t := template.Must(template.New("RangeExample").Parse(`
{{range $i, $x := $.People}}
Index={{$i}} Name={{$x.Name}} Senior={{$x.Senior}}
{{end}}
`))
ctx := Context{
People: []Person{
{Name: "Mary", Senior: false},
{Name: "Joseph", Senior: true},
},
}
t.Execute(os.Stdout, ctx)
}? 关键注意事项:
- 模板中 $.Field 表示从根数据(传入 Execute 的值)访问其导出字段;若字段未导出,行为等价于访问不存在字段(静默失败,不报错)。
- range 在空切片或 nil 切片上安全,不会 panic,但也不会执行循环体——这正是你“输出为空”的根本原因。
- 若需保持结构体内字段私有(如仅通过方法访问),可提供一个导出的 Getter 方法(如 func (c Context) GetPeople() []Person { return c.people }),并在模板中调用 $.GetPeople。
掌握导出规则是 Go 模板开发的第一道门槛。记住:模板可见性 = Go 导出可见性——没有例外。










