Go模板名称

huangapple go评论89阅读模式
英文:

Go template name

问题

html/template(和text/template)包中,template.New具有以下签名:

func New(name string) *Template

name参数的作用是什么?我已经查阅了文档(以及一些源代码),但没有找到答案。我只是用空字符串实例化所有的模板,似乎没有任何区别。为什么我要关心模板的名称?

即使是为了给模板命名,这两种方式似乎是等效的:

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

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

得分: 63

模板的名称(毫不奇怪)是为了给模板命名。

它有什么用呢?只要你不想引用模板,那么名称并不重要。但是如果你想引用它,那么是的,你可以通过它的名称来引用。

什么时候你会想要引用它呢?当你想要在另一个模板中包含一个模板时,例如使用{{template}}操作,或者当你想要执行一个特定的模板时,使用Template.ExecuteTemplate()

到目前为止还好,但还有一个关键的缺失点。这并不是一目了然/微不足道的:template.Template值是“解析模板的表示”。但是这里的措辞有点“不完美”。template.Template值可能是(通常是)多个关联模板的集合。template.Template有一个未导出的字段:

tmpl   map[string]*Template // 从名称到定义的模板的映射。

这个tmpl字段保存了所有其他关联模板,这些模板对模板可见,并且可以通过它们的名称引用。

当你一次解析多个模板时,使用Template.ParseFiles()Template.ParseGlob(),那么模板将以文件名命名,并且它们将自动关联(上述函数返回一个单独的template.Template值,其中包含所有解析的模板,关联)。Template.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))

    // 省略错误检查以简洁起见
    // 执行默认的"one":
    t.Execute(os.Stdout, nil)

    // 执行显式的"one":
    t.ExecuteTemplate(os.Stdout, "one", nil)

    // 执行显式的"other":
    t.ExecuteTemplate(os.Stdout, "other", nil)
}

const t1src = `我是一些模板。
`
const t2src = `我是一些其他模板。
`

输出(在Go Playground上尝试):

我是一些模板。
我是一些模板。
我是一些其他模板。

如果你现在继续,将前两行改为:

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

那么这里发生的是我们将一个新的template.Template值赋给了t,它是解析t2src的结果,所以它将成为默认值,但仍然可以从中“访问”两个模板,因为它们是关联的。输出将更改为(在Go Playground上尝试):

我是一些其他模板。
我是一些模板。
我是一些其他模板。

调用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 = `我是一些模板。{{block "embedded" .}}我被嵌入在"one"中。
{{end}}`
const t2src = `我是一些其他模板。
`
const t3src = `我是第三个,包括来自"one"的所有内容:{{template "one"}}
`

输出(在Go Playground上尝试):

我是一些模板。我被嵌入在"one"中。
我是一些模板。我被嵌入在"one"中。
我是一些其他模板。
我被嵌入在"one"中。
我是第三个,包括来自"one"的所有内容:我是一些模板。我被嵌入在"one"中。

现在应该很明显模板名称的作用以及它来自哪里了。

英文:

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

得分: 5

它用于渲染相关的模板。

例如:

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

输出:

         Start of base template

         
           Body
        

         End of base template
     	
         Start of baz template

         
           Body
        

         End of baz template

tmpl.ExecuteTemplate(os.Stdout, "base", nil) 将使用 "base" 模板渲染模板。

tmpl.ExecuteTemplate(os.Stdout, "baz", nil) 将使用 "baz" 模板渲染模板。

英文:

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

答案3

得分: 3

如果您不需要名称,可以直接使用new内置函数和template.Template

package main

import (
   "os"
   "text/template"
)

func main() {
   t, err := new(template.Template).Parse("hello {{.}}\n")
   if err != nil {
      panic(err)
   }
   t.Execute(os.Stdout, "world")
}
英文:

If you don't need the name, you can just use the new builtin with
template.Template:

package main

import (
   "os"
   "text/template"
)

func main() {
   t, err := new(template.Template).Parse("hello {{.}}\n")
   if err != nil {
      panic(err)
   }
   t.Execute(os.Stdout, "world")
}

huangapple
  • 本文由 发表于 2016年12月16日 10:24:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/41176355.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定