
Go 标准库的 text/template 不支持直接用 {{$var := template "name"}} 捕获模板执行结果,但可通过自定义函数结合 ExecuteTemplate 与 bytes.Buffer 实现变量赋值。
go 标准库的 `text/template` 不支持直接用 `{{$var := template "name"}}` 捕获模板执行结果,但可通过自定义函数结合 `executetemplate` 与 `bytes.buffer` 实现变量赋值。
在 Go 模板中,template 动作仅用于直接渲染(即向输出流写入内容),它本身不返回值,因此无法用于赋值操作——这也是出现 unexpected <template> in operand</template> 错误的根本原因。要实现“捕获子模板输出到变量”,需借助外部 Go 函数完成模板执行与结果收集。
核心思路是:
✅ 注册一个自定义模板函数(如 execTempl);
✅ 在该函数内创建 *bytes.Buffer 作为临时输出目标;
✅ 调用 t.ExecuteTemplate(buf, name, data) 执行指定命名模板;
✅ 返回 buf.String() 作为可被模板变量接收的字符串值。
以下为完整、可运行的示例:
package main
import (
"bytes"
"os"
"text/template"
)
var t *template.Template
func execTempl(name string) (string, error) {
buf := &bytes.Buffer{}
err := t.ExecuteTemplate(buf, name, nil) // 第三个参数可传入任意上下文数据
return buf.String(), err
}
func main() {
const tmpl = `{{define "my-template"}}Hello, {{.Name | default "World"}}!{{end}}
Result captured:
{{$var := execTempl "my-template"}}
"{{$var}}"
`
t = template.Must(template.New("").Funcs(template.FuncMap{
"execTempl": execTempl,
}).Parse(tmpl))
if err := t.Execute(os.Stdout, map[string]string{"Name": "Go"}); err != nil {
panic(err)
}
}
输出结果:
Result captured: "Hello, Go!"
⚠️ 注意事项:
-
execTempl函数中调用的t.ExecuteTemplate必须使用同一模板实例(即全局t),否则会因模板未定义而报错; - 若子模板依赖上下文数据(如
{{.Title}}),需确保execTempl中传入正确的数据(例如t.ExecuteTemplate(buf, name, .)支持继承当前作用域); - 避免在
execTempl中递归调用自身或触发无限模板嵌套,否则将导致栈溢出; - 该方案适用于逻辑简单、非高频调用的场景;若需大量动态模板拼接,建议在 Go 层预处理,而非在模板中过度依赖
execTempl。
通过此方法,你既能保持模板的声明式表达力,又能灵活复用和组合模板片段——真正实现「模板即值」的可控抽象。










