在html/template(和text/template)包中,template.New具有以下签名:
func New(name string) *Template
Run Code Online (Sandbox Code Playgroud)
究竟name用于什么?我已经扫描了文档(以及一些来源),但无济于事.我只是用空字符串实例化我的所有模板,它似乎没有什么区别.我为什么要打扰一个名字?
即使对于命名模板,这两者似乎是等价的:
template.Must(template.New("").Parse(`{{ define "body" }}Body{{ end }}`))
template.Must(template.New("body").Parse(`Body`))
Run Code Online (Sandbox Code Playgroud)
icz*_*cza 30
模板的名称 - 不出所料 - 是命名模板.
到底有什么好处呢?只要您不想参考模板,它就不重要了.但是如果你想引用它,那么是的,你可以通过它的名字来引用它.
你什么时候想参考它?当您想要在另一个模板中包含模板时,例如使用{{template}}操作,或者您想要使用执行特定模板时Template.ExecuteTemplate().
到目前为止一切顺利,但仍有一个缺失的关键点.这不是明确/微不足道的:template.Template值是"解析模板的表示".但这里的措辞有点"不完美".甲template.Template值可以是(并且通常是)的倍数,相关联的模板的集合.template.Template有一个未被报告的领域:
tmpl map[string]*Template // Map from name to defined templates.
Run Code Online (Sandbox Code Playgroud)
此tmpl字段包含所有其他关联的模板,模板可见的模板,以及可由其名称引用的模板.
当您使用或一次解析多个模板时,模板将按文件名命名,并且它们将自动关联(上述函数返回单个值,该值保存所有已解析的模板,并关联).Doc 明确表示:Template.ParseFiles()Template.ParseGlob()template.TemplateTemplate.ParseFiles()
ParseFiles创建一个新模板,并从命名文件中解析模板定义.返回的模板名称将具有第一个文件的基本名称和已解析的内容.[...]
在不同目录中解析具有相同名称的多个文件时,提到的最后一个文件将是结果.例如,ParseFiles("a/foo","b/foo")将"b/foo"存储为名为"foo"的模板,而"a/foo"不可用.
模板名称可以来自多个位置:
{{define "somename"}}或{{block "somename"}}动作定义),template.New()(函数)或Template.New()(方法)的参数.我们来看一些例子:
func main() {
t := template.Must(template.New("one").Parse(t1src))
template.Must(t.New("other").Parse(t2src))
// error checks omitted for brevity
// Executes default, "one":
t.Execute(os.Stdout, nil)
// Executes explicit, "one":
t.ExecuteTemplate(os.Stdout, "one", nil)
// Executes explicit, "other":
t.ExecuteTemplate(os.Stdout, "other", nil)
}
const t1src = `I'm some template.
`
const t2src = `I'm some OTHER template.
`
Run Code Online (Sandbox Code Playgroud)
输出(在Go Playground上试试):
I'm some template.
I'm some template.
I'm some OTHER template.
Run Code Online (Sandbox Code Playgroud)
如果您现在继续,并将前两行更改为:
t := template.Must(template.New("one").Parse(t1src))
t = template.Must(t.New("other").Parse(t2src))
Run Code Online (Sandbox Code Playgroud)
那么这里发生的是我们分配了一个新template.Template值t,这是解析的结果t2src,因此这将是默认值,但是两个模板仍然可以从它们"到达"它们相关联.输出更改为此(在Go Playground上尝试):
I'm some OTHER template.
I'm some template.
I'm some OTHER template.
Run Code Online (Sandbox Code Playgroud)
调用template.New()(函数)创建一个与无关联的新模板.调用Template.New()(方法)时,返回的模板将与调用该方法的(全部)模板相关联.
现在让我们看一些关于"嵌入式"模板的例子.
func main() {
t := template.Must(template.New("one").Parse(t1src))
template.Must(t.New("other").Parse(t2src))
template.Must(t.New("third").Parse(t3src))
t.Execute(os.Stdout, nil)
t.ExecuteTemplate(os.Stdout, "one", nil)
t.ExecuteTemplate(os.Stdout, "other", nil)
t.ExecuteTemplate(os.Stdout, "embedded", nil)
t.ExecuteTemplate(os.Stdout, "third", nil)
}
const t1src = `I'm some template. {{block "embedded" .}}I'm embedded in "one".
{{end}}`
const t2src = `I'm some OTHER template.
`
const t3src = `I'm the 3rd, including everything from "one": {{template "one"}}
`
Run Code Online (Sandbox Code Playgroud)
输出(在Go Playground上试试):
I'm some template. I'm embedded in "one".
I'm some template. I'm embedded in "one".
I'm some OTHER template.
I'm embedded in "one".
I'm the 3rd, including everything from "one": I'm some template. I'm embedded in "one".
Run Code Online (Sandbox Code Playgroud)
现在应该很清楚模板名称的作用是什么,以及它来自何处.
它用于呈现关联的模板。
例如:
tmpl := template.Must(template.New("body").Parse(`
{{ define "body" }}
Body
{{ end }}
`))
tmpl = template.Must(tmpl.New("base").Parse(`
Start of base template
{{ template "body" }}
End of base template
`))
tmpl = template.Must(tmpl.New("baz").Parse(`
Start of baz template
{{ template "body" }}
End of baz template
`))
tmpl.ExecuteTemplate(os.Stdout, "base", nil)
tmpl.ExecuteTemplate(os.Stdout, "baz", nil)
Run Code Online (Sandbox Code Playgroud)
输出:
Start of base template
Body
End of base template
Start of baz template
Body
End of baz template
Run Code Online (Sandbox Code Playgroud)
tmpl.ExecuteTemplate(os.Stdout, "base", nil) 将使用“基本”模板呈现模板
tmpl.ExecuteTemplate(os.Stdout, "baz", nil) 将使用“baz”模板渲染模板