# package template

`import "text/template"`

template包实现了数据驱动的用于生成文本输出的模板。

如果要生成HTML格式的输出，参见html/template包，该包提供了和本包相同的接口，但会自动将输出转化为安全的HTML格式输出，可以抵抗一些网络攻击。

通过将模板应用于一个数据结构（即该数据结构作为模板的参数）来执行，来获得输出。模板中的注释引用数据接口的元素（一般如结构体的字段或者字典的键）来控制执行过程和获取需要呈现的值。模板执行时会遍历结构并将指针表示为'.'（称之为"dot"）指向运行过程中数据结构的当前位置的值。

用作模板的输入文本必须是utf-8编码的文本。"Action"—数据运算和控制单位—由"{{"和"}}"界定；在Action之外的所有文本都不做修改的拷贝到输出中。Action内部不能有换行，但注释可以有换行。

经解析生成模板后，一个模板可以安全的并发执行。

下面是一个简单的例子，可以打印"17 of wool"。

    type Inventory struct {
    	Material string
    	Count    uint
    }
    sweaters := Inventory{"wool", 17}
    tmpl, err := template.New("test").Parse("{{.Count}} of {{.Material}}")
    if err != nil { panic(err) }
    err = tmpl.Execute(os.Stdout, sweaters)
    if err != nil { panic(err) }

更复杂的例子在下面。

### Actions

下面是一个action（动作）的列表。"Arguments"和"pipelines"代表数据的执行结果，细节定义在后面。

    {{/* a comment */}}
        注释，执行时会忽略。可以多行。注释不能嵌套，并且必须紧贴分界符始止，就像这里表示的一样。
    {{pipeline}}
        pipeline的值的默认文本表示会被拷贝到输出里。
    {{if pipeline}} T1 {{end}}
        如果pipeline的值为empty，不产生输出，否则输出T1执行结果。不改变dot的值。
        Empty值包括false、0、任意nil指针或者nil接口，任意长度为0的数组、切片、字典。
    {{if pipeline}} T1 {{else}} T0 {{end}}
        如果pipeline的值为empty，输出T0执行结果，否则输出T1执行结果。不改变dot的值。
    {{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
        用于简化if-else链条，else action可以直接包含另一个if；等价于：
            {{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}}
    {{range pipeline}} T1 {{end}}
        pipeline的值必须是数组、切片、字典或者通道。
        如果pipeline的值其长度为0，不会有任何输出；
        否则dot依次设为数组、切片、字典或者通道的每一个成员元素并执行T1；
        如果pipeline的值为字典，且键可排序的基本类型，元素也会按键的顺序排序。
    {{range pipeline}} T1 {{else}} T0 {{end}}
        pipeline的值必须是数组、切片、字典或者通道。
        如果pipeline的值其长度为0，不改变dot的值并执行T0；否则会修改dot并执行T1。
    {{template "name"}}
        执行名为name的模板，提供给模板的参数为nil，如模板不存在输出为""
    {{template "name" pipeline}}
        执行名为name的模板，提供给模板的参数为pipeline的值。
    {{with pipeline}} T1 {{end}}
        如果pipeline为empty不产生输出，否则将dot设为pipeline的值并执行T1。不修改外面的dot。
    {{with pipeline}} T1 {{else}} T0 {{end}}
        如果pipeline为empty，不改变dot并执行T0，否则dot设为pipeline的值并执行T1。

### Arguments

参数代表一个简单的，由下面的某一条表示的值：

    - go语法的布尔值、字符串、字符、整数、浮点数、虚数、复数，视为无类型字面常数，字符串不能跨行
    - 关键字nil，代表一个go的无类型的nil值
    - 字符'.'（句点，用时不加单引号），代表dot的值
    - 变量名，以美元符号起始加上（可为空的）字母和数字构成的字符串，如：$piOver2和$；
      执行结果为变量的值，变量参见下面的介绍
    - 结构体数据的字段名，以句点起始，如：.Field；
      执行结果为字段的值，支持链式调用：.Field1.Field2；
      字段也可以在变量上使用（包括链式调用）：$x.Field1.Field2；
    - 字典类型数据的键名；以句点起始，如：.Key；
      执行结果是该键在字典中对应的成员元素的值；
      键也可以和字段配合做链式调用，深度不限：.Field1.Key1.Field2.Key2；
      虽然键也必须是字母和数字构成的标识字符串，但不需要以大写字母起始；
      键也可以用于变量（包括链式调用）：$x.key1.key2；
    - 数据的无参数方法名，以句点为起始，如：.Method；
      执行结果为dot调用该方法的返回值，dot.Method()；
      该方法必须有1到2个返回值，如果有2个则后一个必须是error接口类型；
      如果有2个返回值的方法返回的error非nil，模板执行会中断并返回给调用模板执行者该错误；
      方法可和字段、键配合做链式调用，深度不限：.Field1.Key1.Method1.Field2.Key2.Method2；
      方法也可以在变量上使用（包括链式调用）：$x.Method1.Field；
    - 无参数的函数名，如：fun；
      执行结果是调用该函数的返回值fun()；对返回值的要求和方法一样；函数和函数名细节参见后面。
    - 上面某一条的实例加上括弧（用于分组）
      执行结果可以访问其字段或者键对应的值：
          print (.F1 arg1) (.F2 arg2)
          (.StructValuedMethod "arg").Field

Arguments可以是任何类型：如果是指针，在必要时会自动表示为指针指向的值；如果执行结果生成了一个函数类型的值，如结构体的函数类型字段，该函数不会自动调用，但可以在if等action里视为真。如果要调用它，使用call函数，参见下面。

Pipeline是一个（可能是链状的）command序列。Command可以是一个简单值（argument）或者对函数或者方法的（可以有多个参数的）调用：

    Argument
        执行结果是argument的执行结果
    .Method [Argument...]
        方法可以独立调用或者位于链式调用的末端，不同于链式调用中间的方法，可以使用参数；
        执行结果是使用给出的参数调用该方法的返回值：dot.Method(Argument1, etc.)；
    functionName [Argument...]
        执行结果是使用给定的参数调用函数名指定的函数的返回值：function(Argument1, etc.)；

### Pipelines

pipeline通常是将一个command序列分割开，再使用管道符'|'连接起来（但不使用管道符的command序列也可以视为一个管道）。在一个链式的pipeline里，每个command的结果都作为下一个command的最后一个参数。pipeline最后一个command的输出作为整个管道执行的结果。

command的输出可以是1到2个值，如果是2个后一个必须是error接口类型。如果error类型返回值非nil，模板执行会中止并将该错误返回给执行模板的调用者。

### Variables

Action里可以初始化一个变量来捕获管道的执行结果。初始化语法如下：

    $variable := pipeline

其中$variable是变量的名字。声明变量的action不会产生任何输出。

如果"range" action初始化了1个变量，该变量设置为迭代器的每一个成员元素，如果初始化了逗号分隔的2个变量：

    range $index, $element := pipeline

这时，$index和$element分别设置为数组/切片的索引或者字典的键，以及对应的成员元素。注意这和go range从句只有一个参数时设置为索引/键不同！

一个变量的作用域只到声明它的控制结构（"if"、"with"、"range"）的"end"为止，如果不是在控制结构里声明会直到模板结束为止。子模板的调用不会从调用它的位置（作用域）继承变量。

模板开始执行时，$会设置为传递给Execute方法的参数，就是说，dot的初始值。

### Examples

下面是一些单行模板，展示了pipeline和变量。所有都生成加引号的单词"output"：

    {{"\"output\""}}
    	字符串常量
    {{`"output"`}}
    	原始字符串常量
    {{printf "%q" "output"}}
    	函数调用
    {{"output" | printf "%q"}}
    	函数调用，最后一个参数来自前一个command的返回值
    {{printf "%q" (print "out" "put")}}
    	加括号的参数
    {{"put" | printf "%s%s" "out" | printf "%q"}}
    	玩出花的管道的链式调用
    {{"output" | printf "%s" | printf "%q"}}
    	管道的链式调用
    {{with "output"}}{{printf "%q" .}}{{end}}
    	使用dot的with action
    {{with $x := "output" | printf "%q"}}{{$x}}{{end}}
    	创建并使用变量的with action
    {{with $x := "output"}}{{printf "%q" $x}}{{end}}
    	将变量使用在另一个action的with action
    {{with $x := "output"}}{{$x | printf "%q"}}{{end}}
    	以管道形式将变量使用在另一个action的with action

### Functions

执行模板时，函数从两个函数字典中查找：首先是模板函数字典，然后是全局函数字典。一般不在模板内定义函数，而是使用Funcs方法添加函数到模板里。

预定义的全局函数如下：

    and
        函数返回它的第一个empty参数或者最后一个参数；
        就是说"and x y"等价于"if x then y else x"；所有参数都会执行；
    or
        返回第一个非empty参数或者最后一个参数；
        亦即"or x y"等价于"if x then x else y"；所有参数都会执行；
    not
        返回它的单个参数的布尔值的否定
    len
        返回它的参数的整数类型长度
    index
        执行结果为第一个参数以剩下的参数为索引/键指向的值；
        如"index x 1 2 3"返回x[1][2][3]的值；每个被索引的主体必须是数组、切片或者字典。
    print
        即fmt.Sprint
    printf
        即fmt.Sprintf
    println
        即fmt.Sprintln
    html
        返回其参数文本表示的HTML逸码等价表示。
    urlquery
        返回其参数文本表示的可嵌入URL查询的逸码等价表示。
    js
        返回其参数文本表示的JavaScript逸码等价表示。
    call
        执行结果是调用第一个参数的返回值，该参数必须是函数类型，其余参数作为调用该函数的参数；
        如"call .X.Y 1 2"等价于go语言里的dot.X.Y(1, 2)；
        其中Y是函数类型的字段或者字典的值，或者其他类似情况；
        call的第一个参数的执行结果必须是函数类型的值（和预定义函数如print明显不同）；
        该函数类型值必须有1到2个返回值，如果有2个则后一个必须是error接口类型；
        如果有2个返回值的方法返回的error非nil，模板执行会中断并返回给调用模板执行者该错误；

布尔函数会将任何类型的零值视为假，其余视为真。

下面是定义为函数的二元比较运算的集合：

    eq      如果arg1 == arg2则返回真
    ne      如果arg1 != arg2则返回真
    lt      如果arg1 < arg2则返回真
    le      如果arg1 <= arg2则返回真
    gt      如果arg1 > arg2则返回真
    ge      如果arg1 >= arg2则返回真

为了简化多参数相等检测，eq（只有eq）可以接受2个或更多个参数，它会将第一个参数和其余参数依次比较，返回下式的结果：

    arg1==arg2 || arg1==arg3 || arg1==arg4 ...

（和go的||不一样，不做惰性运算，所有参数都会执行）

比较函数只适用于基本类型（或重定义的基本类型，如"type Celsius float32"）。它们实现了go语言规则的值的比较，但具体的类型和大小会忽略掉，因此任意类型有符号整数值都可以互相比较；任意类型无符号整数值都可以互相比较；等等。但是，整数和浮点数不能互相比较。

### Associated templates

每一个模板在创建时都要用一个字符串命名。同时，每一个模板都会和0或多个模板关联，并可以使用它们的名字调用这些模板；这种关联可以传递，并形成一个模板的名字空间。

一个模板可以通过模板调用实例化另一个模板；参见上面的"template" action。name必须是包含模板调用的模板相关联的模板的名字。

### Nested template definitions

当解析模板时，可以定义另一个模板，该模板会和当前解析的模板相关联。模板必须定义在当前模板的最顶层，就像go程序里的全局变量一样。

这种定义模板的语法是将每一个子模板的声明放在"define"和"end" action内部。

define action使用给出的字符串常数给模板命名，举例如下：

    `{{define "T1"}}ONE{{end}}
    {{define "T2"}}TWO{{end}}
    {{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}}
    {{template "T3"}}`

它定义了两个模板T1和T2，第三个模板T3在执行时调用这两个模板；最后该模板调用了T3。输出结果是：

    ONE TWO

采用这种方法，一个模板只能从属于一个关联。如果需要让一个模板可以被多个关联查找到；模板定义必须多次解析以创建不同的*Template 值，或者必须使用Clone或AddParseTree方法进行拷贝。

可能需要多次调用Parse函数以集合多个相关的模板；参见ParseFiles和ParseGlob函数和方法，它们提供了简便的途径去解析保存在文件中的存在关联的模板。

一个模板可以直接调用或者通过ExecuteTemplate方法调用指定名字的相关联的模板；我们可以这样调用模板：

    err := tmpl.Execute(os.Stdout, "no data needed")
    if err != nil {
    	log.Fatalf("execution failed: %s", err)
    }

或显式的指定模板的名字来调用：

    err := tmpl.ExecuteTemplate(os.Stdout, "T2", "no data needed")
    if err != nil {
    	log.Fatalf("execution failed: %s", err)
    }

## func HTMLEscape

    func HTMLEscape(w io.Writer, b []byte)

函数向w中写入b的HTML转义等价表示。

## func HTMLEscapeString

    func HTMLEscapeString(s string) string

返回s的HTML转义等价表示字符串。

## func HTMLEscaper

    func HTMLEscaper(args ...interface{}) string

函数返回其所有参数文本表示的HTML转义等价表示字符串。

## func JSEscape

    func JSEscape(w io.Writer, b []byte)

函数向w中写入b的JavaScript转义等价表示。

## func JSEscapeString

    func JSEscapeString(s string) string

返回s的JavaScript转义等价表示字符串。

## func JSEscaper

    func JSEscaper(args ...interface{}) string

函数返回其所有参数文本表示的JavaScript转义等价表示字符串。

## func URLQueryEscaper

    func URLQueryEscaper(args ...interface{}) string

函数返回其所有参数文本表示的可以嵌入URL查询的转义等价表示字符串。

## type FuncMap

    type FuncMap map[string]interface{}

FuncMap类型定义了函数名字符串到函数的映射，每个函数都必须有1到2个返回值，如果有2个则后一个必须是error接口类型；如果有2个返回值的方法返回的error非nil，模板执行会中断并返回给调用者该错误。

## type Template

    type Template struct {
        *parse.Tree
        // 内含隐藏或非导出字段
    }

代表一个解析好的模板，*parse.Tree字段仅仅是暴露给html/template包使用的，因此其他人应该视字段未导出。

Example

    // Define a template.
    const letter = `
    Dear {{.Name}},
    {{if .Attended}}
    It was a pleasure to see you at the wedding.{{else}}
    It is a shame you couldn't make it to the wedding.{{end}}
    {{with .Gift}}Thank you for the lovely {{.}}.
    {{end}}
    Best wishes,
    Josie
    `
    // Prepare some data to insert into the template.
    type Recipient struct {
        Name, Gift string
        Attended   bool
    }
    var recipients = []Recipient{
        {"Aunt Mildred", "bone china tea set", true},
        {"Uncle John", "moleskin pants", false},
        {"Cousin Rodney", "", false},
    }
    // Create a new template and parse the letter into it.
    t := template.Must(template.New("letter").Parse(letter))
    // Execute the template for each recipient.
    for _, r := range recipients {
        err := t.Execute(os.Stdout, r)
        if err != nil {
            log.Println("executing template:", err)
        }
    }

Output:

    Dear Aunt Mildred,
    It was a pleasure to see you at the wedding.
    Thank you for the lovely bone china tea set.
    Best wishes,
    Josie
    Dear Uncle John,
    It is a shame you couldn't make it to the wedding.
    Thank you for the lovely moleskin pants.
    Best wishes,
    Josie
    Dear Cousin Rodney,
    It is a shame you couldn't make it to the wedding.
    Best wishes,
    Josie

Example (Func)

    // First we create a FuncMap with which to register the function.
    funcMap := template.FuncMap{
        // The name "title" is what the function will be called in the template text.
        "title": strings.Title,
    }
    // A simple template definition to test our function.
    // We print the input text several ways:
    // - the original
    // - title-cased
    // - title-cased and then printed with %q
    // - printed with %q and then title-cased.
    const templateText = `
    Input: {{printf "%q" .}}
    Output 0: {{title .}}
    Output 1: {{title . | printf "%q"}}
    Output 2: {{printf "%q" . | title}}
    `
    // Create a template, add the function map, and parse the text.
    tmpl, err := template.New("titleTest").Funcs(funcMap).Parse(templateText)
    if err != nil {
        log.Fatalf("parsing: %s", err)
    }
    // Run the template to verify the output.
    err = tmpl.Execute(os.Stdout, "the go programming language")
    if err != nil {
        log.Fatalf("execution: %s", err)
    }

Output:

    Input: "the go programming language"
    Output 0: The Go Programming Language
    Output 1: "The Go Programming Language"
    Output 2: "The Go Programming Language"

Example (Glob)

    // Here we create a temporary directory and populate it with our sample
    // template definition files; usually the template files would already
    // exist in some location known to the program.
    dir := createTestDir([]templateFile{
        // T0.tmpl is a plain template file that just invokes T1.
        {"T0.tmpl", `T0 invokes T1: ({{template "T1"}})`},
        // T1.tmpl defines a template, T1 that invokes T2.
        {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
        // T2.tmpl defines a template T2.
        {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
    })
    // Clean up after the test; another quirk of running as an example.
    defer os.RemoveAll(dir)
    // pattern is the glob pattern used to find all the template files.
    pattern := filepath.Join(dir, "*.tmpl")
    // Here starts the example proper.
    // T0.tmpl is the first name matched, so it becomes the starting template,
    // the value returned by ParseGlob.
    tmpl := template.Must(template.ParseGlob(pattern))
    err := tmpl.Execute(os.Stdout, nil)
    if err != nil {
        log.Fatalf("template execution: %s", err)
    }

Output:

    T0 invokes T1: (T1 invokes T2: (This is T2))

Example (Helpers)

    // Here we create a temporary directory and populate it with our sample
    // template definition files; usually the template files would already
    // exist in some location known to the program.
    dir := createTestDir([]templateFile{
        // T1.tmpl defines a template, T1 that invokes T2.
        {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
        // T2.tmpl defines a template T2.
        {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
    })
    // Clean up after the test; another quirk of running as an example.
    defer os.RemoveAll(dir)
    // pattern is the glob pattern used to find all the template files.
    pattern := filepath.Join(dir, "*.tmpl")
    // Here starts the example proper.
    // Load the helpers.
    templates := template.Must(template.ParseGlob(pattern))
    // Add one driver template to the bunch; we do this with an explicit template definition.
    _, err := templates.Parse("{{define `driver1`}}Driver 1 calls T1: ({{template `T1`}})\n{{end}}")
    if err != nil {
        log.Fatal("parsing driver1: ", err)
    }
    // Add another driver template.
    _, err = templates.Parse("{{define `driver2`}}Driver 2 calls T2: ({{template `T2`}})\n{{end}}")
    if err != nil {
        log.Fatal("parsing driver2: ", err)
    }
    // We load all the templates before execution. This package does not require
    // that behavior but html/template's escaping does, so it's a good habit.
    err = templates.ExecuteTemplate(os.Stdout, "driver1", nil)
    if err != nil {
        log.Fatalf("driver1 execution: %s", err)
    }
    err = templates.ExecuteTemplate(os.Stdout, "driver2", nil)
    if err != nil {
        log.Fatalf("driver2 execution: %s", err)
    }

Output:

    Driver 1 calls T1: (T1 invokes T2: (This is T2))
    Driver 2 calls T2: (This is T2)

Example (Share)

    // Here we create a temporary directory and populate it with our sample
    // template definition files; usually the template files would already
    // exist in some location known to the program.
    dir := createTestDir([]templateFile{
        // T0.tmpl is a plain template file that just invokes T1.
        {"T0.tmpl", "T0 ({{.}} version) invokes T1: ({{template `T1`}})\n"},
        // T1.tmpl defines a template, T1 that invokes T2. Note T2 is not defined
        {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
    })
    // Clean up after the test; another quirk of running as an example.
    defer os.RemoveAll(dir)
    // pattern is the glob pattern used to find all the template files.
    pattern := filepath.Join(dir, "*.tmpl")
    // Here starts the example proper.
    // Load the drivers.
    drivers := template.Must(template.ParseGlob(pattern))
    // We must define an implementation of the T2 template. First we clone
    // the drivers, then add a definition of T2 to the template name space.
    // 1. Clone the helper set to create a new name space from which to run them.
    first, err := drivers.Clone()
    if err != nil {
        log.Fatal("cloning helpers: ", err)
    }
    // 2. Define T2, version A, and parse it.
    _, err = first.Parse("{{define `T2`}}T2, version A{{end}}")
    if err != nil {
        log.Fatal("parsing T2: ", err)
    }
    // Now repeat the whole thing, using a different version of T2.
    // 1. Clone the drivers.
    second, err := drivers.Clone()
    if err != nil {
        log.Fatal("cloning drivers: ", err)
    }
    // 2. Define T2, version B, and parse it.
    _, err = second.Parse("{{define `T2`}}T2, version B{{end}}")
    if err != nil {
        log.Fatal("parsing T2: ", err)
    }
    // Execute the templates in the reverse order to verify the
    // first is unaffected by the second.
    err = second.ExecuteTemplate(os.Stdout, "T0.tmpl", "second")
    if err != nil {
        log.Fatalf("second execution: %s", err)
    }
    err = first.ExecuteTemplate(os.Stdout, "T0.tmpl", "first")
    if err != nil {
        log.Fatalf("first: execution: %s", err)
    }

Output:

    T0 (second version) invokes T1: (T1 invokes T2: (T2, version B))
    T0 (first version) invokes T1: (T1 invokes T2: (T2, version A))

### func Must

    func Must(t *Template, err error) *Template

Must函数用于包装返回(*Template, error)的函数/方法调用，它会在err非nil时panic，一般用于变量初始化：

    var t = template.Must(template.New("name").Parse("text"))

### func New

    func New(name string) *Template

创建一个名为name的模板。

### func ParseFiles

    func ParseFiles(filenames ...string) (*Template, error)

ParseFiles函数创建一个模板并解析filenames指定的文件里的模板定义。返回的模板的名字是第一个文件的文件名（不含扩展名），内容为解析后的第一个文件的内容。至少要提供一个文件。如果发生错误，会停止解析并返回nil。

### func ParseGlob

    func ParseGlob(pattern string) (*Template, error)

ParseGlob创建一个模板并解析匹配pattern的文件（参见glob规则）里的模板定义。返回的模板的名字是第一个匹配的文件的文件名（不含扩展名），内容为解析后的第一个文件的内容。至少要存在一个匹配的文件。如果发生错误，会停止解析并返回nil。ParseGlob等价于使用匹配pattern的文件的列表为参数调用ParseFiles。

### func (*Template) Name

    func (t *Template) Name() string

返回模板t的名字。

### func (*Template) Delims

    func (t *Template) Delims(left, right string) *Template

Delims方法用于设置action的分界字符串，应用于之后的Parse、ParseFiles、ParseGlob方法。嵌套模板定义会继承这种分界符设置。空字符串分界符表示相应的默认分界符：{{或}}。返回值就是t，以便进行链式调用。

### func (*Template) Funcs

    func (t *Template) Funcs(funcMap FuncMap) *Template

Funcs方法向模板t的函数字典里加入参数funcMap内的键值对。如果funcMap某个键值对的值不是函数类型或者返回值不符合要求会panic。但是，可以对t函数列表的成员进行重写。方法返回t以便进行链式调用。

### func (*Template) Clone

    func (t *Template) Clone() (*Template, error)

Clone方法返回模板的一个副本，包括所有相关联的模板。模板的底层表示树并未拷贝，而是拷贝了命名空间，因此拷贝调用Parse方法不会修改原模板的命名空间。Clone方法用于准备模板的公用部分，向拷贝中加入其他关联模板后再进行使用。

### func (*Template) Lookup

    func (t *Template) Lookup(name string) *Template

Lookup方法返回与t关联的名为name的模板，如果没有这个模板返回nil。

### func (*Template) Templates

    func (t *Template) Templates() []*Template

Templates方法返回与t相关联的模板的切片，包括t自己。

### func (*Template) New

    func (t *Template) New(name string) *Template

New方法创建一个和t关联的名字为name的模板并返回它。这种可以传递的关联允许一个模板使用template action调用另一个模板。

### func (*Template) AddParseTree

    func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error)

AddParseTree方法使用name和tree创建一个模板并使它和t相关联。

### func (*Template) Parse

    func (t *Template) Parse(text string) (*Template, error)

Parse方法将字符串text解析为模板。嵌套定义的模板会关联到最顶层的t。Parse可以多次调用，但只有第一次调用可以包含空格、注释和模板定义之外的文本。如果后面的调用在解析后仍剩余文本会引发错误、返回nil且丢弃剩余文本；如果解析得到的模板已有相关联的同名模板，会覆盖掉原模板。

### func (*Template) ParseFiles

    func (t *Template) ParseFiles(filenames ...string) (*Template, error)

ParseGlob方法解析filenames指定的文件里的模板定义并将解析结果与t关联。如果发生错误，会停止解析并返回nil，否则返回(t, nil)。至少要提供一个文件。

### func (*Template) ParseGlob

    func (t *Template) ParseGlob(pattern string) (*Template, error)

ParseFiles方法解析匹配pattern的文件里的模板定义并将解析结果与t关联。如果发生错误，会停止解析并返回nil，否则返回(t, nil)。至少要存在一个匹配的文件。

### func (*Template) Execute

    func (t *Template) Execute(wr io.Writer, data interface{}) (err error)

Execute方法将解析好的模板应用到data上，并将输出写入wr。如果执行时出现错误，会停止执行，但有可能已经写入wr部分数据。模板可以安全的并发执行。

### func (*Template) ExecuteTemplate

    func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error

ExecuteTemplate方法类似Execute，但是使用名为name的t关联的模板产生输出。