Go Template ParseFiles 函数解析多个文件

The Go Template ParseFiles func parsing multiple files

如果我将两个或更多文件传递给 Go Template 的 ParseFiles 函数会发生什么?

func (*Template) ParseFiles

它帮助说:

ParseFiles parses the named files and associates the resulting templates with t. If an error occurs, parsing stops and the returned template is nil; otherwise it is t. There must be at least one file. Since the templates created by ParseFiles are named by the base names of the argument files, t should usually have the name of one of the (base) names of the files. If it does not, depending on t's contents before calling ParseFiles, t.Execute may fail. In that case use t.ExecuteTemplate to execute a valid template.

When parsing multiple files with the same name in different directories, the last one mentioned will be the one that results.

但我仍然不确定影响输出的差异是什么,因为

MyTempl.ParseFiles(tf1)

对比

MyTempl.ParseFiles(tf1, tf2)

tf2 的内容会附加到 tf1 的内容吗?

首先介绍一下 "template" 概念:

一个template.Template值是"the representation of a parsed template"。但是这里的措辞有点"imperfect"。 template.Template 值可能是(并且通常是)多个关联模板的 集合 template.Template 有一个未导出的字段:

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

tmpl 字段包含所有其他关联的模板,即模板可见的模板,并且可以通过它们的名称引用。

您可以在这个答案中阅读更多相关信息:

回到Template.ParseFiles()方法。此方法从作为参数传递给它的文件中解析多个模板。从文件中解析出的模板将以文件名命名(没有文件夹,只有文件名),并且它们将被添加到方法接收器指定的 t 模板的内部关联模板映射中。

解析后的模板将不会被追加。将为它们创建多个单独的 template.Template 值,但它们将关联(因此它们可以相互引用,例如它们可以相互包含)。

让我们看一个例子。假设我们有这两个模板文件:

a.html 是:

I'm a.

b.html

I'm b.

还有一个示例代码:

t := template.New("a.html")
if _, err := t.ParseFiles("a.html", "b.html"); err != nil {
    panic(err)
}
if err := t.Execute(os.Stdout, nil); err != nil {
    panic(err)
}

此示例创建一个名为 a.html 的新空模板,然后解析 2 个文件:a.htmlb.html.

结果会怎样? t 将表示 a.html 模板,因为我们之前使用该特定名称创建它。 运行 代码,输出将是:

I'm a.

现在,如果我们将第一行更改为:

t := template.New("x.html")

其余的保持不变,运行我们看到类似的东西:

panic: template: "x.html" is an incomplete or empty template

原因是 t 表示一个名为 x.html 的模板,但它是空的,因为我们没有解析任何东西 "into" 它,而且解析的文件也不匹配名字 x.html。因此尝试执行它会导致错误。

现在,如果我们尝试执行其关联的命名模板之一:

if err := t.ExecuteTemplate(os.Stdout, "a.html", nil); err != nil {
    panic(err)
}

成功,再次给出:

I'm a.