Go template name

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.

Leave a Comment