Go template name

两盒软妹~` 提交于 2020-01-09 03:49:06

问题


In the html/template (and text/template) packages, template.New has the following signature:

func New(name string) *Template

What exactly is the name used for? I've scanned the docs (and a bit of source), but to no avail. I just instantiate all of my templates with an empty string and it doesn't seem to make a difference. Why should I bother with a name?

Even for naming templates, the two seem equivalent:

template.Must(template.New("").Parse(`{{ define "body" }}Body{{ end }}`))
template.Must(template.New("body").Parse(`Body`))

https://play.golang.org/p/wKzCHdLf2S


回答1:


The name of the template–unsurprisingly–is to name the template.

What is it good for? As long as you don't want to refer to the template, it doesn't really matter. But if you want to refer to it, then yes, you refer to it by its name.

When would you want to refer to it? When you want to include a template in another e.g. using the {{template}} action, or when you want to execute a specific template using Template.ExecuteTemplate().

So far so good, but there's still a missing key point. This is not unambiguous / trivial: a template.Template value is "the representation of a parsed template". But the wording here is a little "imperfect". A template.Template value may be (and usually is) a collection of multiple, associated templates. template.Template has an unexported field:

tmpl   map[string]*Template // Map from name to defined templates.

This tmpl field holds all other associated templates, templates that are visible to the template, and which can be referred to–yes–by their names.

When you parse multiple templates at once, using Template.ParseFiles() or Template.ParseGlob(), then the templates will be named by the file names, and they will be associated automatically (the above mentioned functions return a single template.Template value, which holds all the parsed templates, associated). Doc of Template.ParseFiles() is clear on this:

ParseFiles creates a new Template and parses the template definitions from the named files. The returned template's name will have the base name and parsed contents of the first file. [...]

When parsing multiple files with the same name in different directories, the last one mentioned will be the one that results. For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template named "foo", while "a/foo" is unavailable.

The template name can come from multiple places:

  • it can come from the file name (as seen above)
  • it can be specified explicitly (if defined using the {{define "somename"}} or {{block "somename"}} actions),
  • or it may be defined as an argument passed to template.New() (function) or Template.New() (method).

Let's see some examples:

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.
`

Output (try it on the Go Playground):

I'm some template.
I'm some template.
I'm some OTHER template.

If you now go ahead, and change the first 2 lines to this:

t := template.Must(template.New("one").Parse(t1src))
t = template.Must(t.New("other").Parse(t2src))

Then what happens here is that we assigned a new template.Template value to t, which was the result of parsing t2src, so that will be the default, but still both templates can be "reached" from it as they are associated. The output changes to this (try it on the Go Playground):

I'm some OTHER template.
I'm some template.
I'm some OTHER template.

Calling template.New() (function) creates a new template, associated to none. When calling Template.New() (method), the returned template will be associated with (all) the template(s) the method is called on.

Now let's see some examples regarding "embedded" templates.

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"}}
`

Output (try it on the 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".

It should be obvious now what the role of the template name is, and where it comes from.




回答2:


It is used to render associated templates.

For instance:

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)

Play Example

Output:

     Start of base template


       Body


     End of base template

     Start of baz template


       Body


     End of baz template

tmpl.ExecuteTemplate(os.Stdout, "base", nil) will render the template using the "base" template

tmpl.ExecuteTemplate(os.Stdout, "baz", nil) will render the template using the "baz" template



来源:https://stackoverflow.com/questions/41176355/go-template-name

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!