<p>text/template核心用法是定义模板、传入导出字段结构体、调用Execute渲染;需注意字段首字母大写、避免nil传参、用{{- -}}控制空白、ParseFiles路径相对os.Getwd()、FuncMap注册函数。</p>

text/template 的核心用法就三步:定义模板、传入结构体数据、调用 Execute 渲染。它不自动转义、不依赖 HTML、不处理 HTTP,就是纯文本生成工具——适合写配置、发邮件、生成代码,但别拿它直接渲染网页。
模板里写 {{.Name}} 却报 “can’t evaluate field Name” 怎么办
这是最常卡住人的错误,本质是 Go 的反射规则在起作用:
- 结构体字段必须首字母大写(
Name✅,name❌),否则text/template看不见 - 不能传
map[string]interface{}后还指望{{.Name}}—— map 没“字段”,只有“键”,得写{{.Name}}才对;但更推荐用结构体,类型安全、IDE 可提示 - 传参必须是结构体值或指针,不能是
nil;t.Execute(w, nil)会 panic,哪怕模板开头有{{if .}} - 调试时加一行
fmt.Printf("%#v\n", data),确认你传进去的真是带导出字段的结构体,不是空 struct 或嵌套错层
想循环或判断,但输出一堆空行和缩进怎么办
text/template 默认照单全收换行和空格,生成代码/配置时特别容易崩格式:
- 用
{{- if .Active}}吞掉前面所有空白(包括换行),{{end -}}吞掉后面换行 -
{{range}}前先加{{if .Items}}判断,避免空切片时还留着无意义的上下文 - 生成 Go 代码时,别靠模板缩进对齐,把逻辑压成单行更稳:
{{range .Fields}}func (t *T) Get{{.Name}}() {{.Type}} { return t.{{.Name}} }{{end}} - 需要美观缩进的 YAML/JSON?别让模板干这事,用
yaml.MarshalIndent或json.MarshalIndent先序列化好,再注入模板
从文件加载模板总提示 “pattern matches no files”
路径问题不是模板语法错,而是运行时工作目录和你想象的不一致:
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
立即学习“go语言免费学习笔记(深入)”;
-
template.ParseFiles("tmpl/hello.tmpl")的路径是相对于os.Getwd(),不是源码所在目录 —— 运行前cd到项目根目录再执行 - 更可靠的方式是
template.ParseGlob("templates/*.tmpl"),或用embed打包进二进制://go:embed templates/*.tmpl+template.ParseFS(tmplFS, "templates/*.tmpl") -
template.Must要用在Parse阶段,它会在解析失败时立刻 panic,省得等到Execute才暴露语法错误
想在模板里调用 strings.Title 或自定义函数
text/template 不允许直接调用未注册函数,连标准库函数都要手动塞进去:
- 必须通过
FuncMap显式注册:t.Funcs(template.FuncMap{"title": strings.Title}) - 注册后才能用管道调用:
{{.Name | title}};写{{title .Name}}也行,但风格不统一 - 结构体方法不能直接调用(哪怕是指针接收者),必须包装成普通函数再注册
- 函数里别做日志、HTTP 请求等副作用操作——模板可能并发执行多次,结果不可控
复杂点在于:模板本身没运行时类型检查,错只在 Execute 时才暴露;而字段可见性、路径层级、空值处理这些细节,又全靠开发者自己盯紧。写完别急着跑,先 fmt.Printf 看数据长啥样,再看模板动作是否真能触达目标字段。

















