
在 go 中使用 `html/template` 时,若主模板通过 `{{template "name"}}` 调用子模板,默认会以 `nil` 数据执行子模板;必须显式传入当前上下文(如 `{{template "name" .}}`)才能让子模板访问结构体字段。
Go 的模板系统采用“作用域隔离”设计:每个 {{template}} 动作默认以空上下文(nil)执行被调用模板,除非显式指定数据源。这正是你遇到 {{.Title}} 和 {{.Page.Test}} 渲染为空的原因——{{template "article"}} 没有传入任何数据,子模板内部的 . 为 nil,字段访问自然失败。
✅ 正确做法是在 core.tmpl 中改为:
{{template "article" .}}这样,当前执行上下文(即 *News 实例)会被完整传递给 article.tmpl,其中 {{.Title}} 和 {{.Page.Test}} 均可正常解析。
完整可运行示例:
立即学习“前端免费学习笔记(深入)”;
package main
import (
"html/template"
"os"
"path/filepath"
)
type Page struct {
Test string
}
type News struct {
Page
Title string
}
func main() {
// 假设模板文件位于当前目录
t, err := template.ParseFiles("core.tmpl", "article.tmpl")
if err != nil {
panic(err)
}
p := &News{
Title: "Go Template Deep Dive",
Page: Page{
Test: "From Embedded Struct",
},
}
err = t.Execute(os.Stdout, p)
if err != nil {
panic(err)
}
}对应模板文件:
core.tmpl:
{{template "article" .}}
article.tmpl:
{{define "article"}}
{{.Title}}
{{.Page.Test}}
{{end}}⚠️ 注意事项:
- . 是模板中的当前数据上下文,必须显式传递才能跨模板共享;
- 若子模板需独立数据(如侧边栏、分页组件),可传入特定字段或新结构体:{{template "sidebar" .SidebarData}};
- 使用 template.ParseGlob 或 template.New("").ParseFiles(...) 可更灵活管理多模板;
- 所有 {{define}} 模板名必须全局唯一,重复定义将导致 ParseFiles 失败。
掌握 {{template "name" pipeline}} 的数据传递机制,是构建模块化 HTML 模板(如布局+内容分离)的基础前提。










