golang 模板中的变量

Variables inside templates in golang

html/text 模板中变量的命名空间是什么?我认为变量 $x 可以更改模板内的值,但这个例子告诉我我不能。

当我尝试根据年份对锦标赛进行分组时我失败了 - 像这样 (http://play.golang.org/p/EX1Aut_ULD):

package main

import (
    "fmt"
    "os"
    "text/template"
    "time"
)

func main() {
    tournaments := []struct {
        Place string
        Date  time.Time
    }{
        // for clarity - date is sorted, we don't need sort it again
        {"Town1", time.Date(2015, time.November, 10, 23, 0, 0, 0, time.Local)},
        {"Town2", time.Date(2015, time.October, 10, 23, 0, 0, 0, time.Local)},
        {"Town3", time.Date(2014, time.November, 10, 23, 0, 0, 0, time.Local)},
    }
    t, err := template.New("").Parse(`
{{$prev_year:=0}}
{{range .}}
    {{with .Date}}
        {{$year:=.Year}}
                    {{if ne $year $prev_year}}
                        Actions in year {{$year}}:
                {{$prev_year:=$year}}
            {{end}}
    {{end}}

        {{.Place}}, {{.Date}}
    {{end}}

    `)
    if err != nil {
        panic(err)
    }
    err = t.Execute(os.Stdout, tournaments)
    if err != nil {
        fmt.Println("executing template:", err)
    }
}

编辑:请参阅 以获得更新的答案。


原回答:

https://golang.org/pkg/text/template/#hdr-Variables:

A variable's scope extends to the "end" action of the control structure ("if", "with", or "range") in which it is declared, or to the end of the template if there is no such control structure.

所以你用 {{$prev_year:=$year}} 定义的 $prev_year 只存在到..下一行 ({{end}}).

似乎没有办法解决这个问题。

"right" 方法是将逻辑从您的模板中取出,然后在您的 Go 代码中进行分组。

这是一个工作示例:https://play.golang.org/p/DZoSXo9WQR

package main

import (
    "fmt"
    "os"
    "text/template"
    "time"
)

type Tournament struct {
    Place string
    Date  time.Time
}

type TournamentGroup struct {
    Year        int
    Tournaments []Tournament
}

func groupTournamentsByYear(tournaments []Tournament) []TournamentGroup {
    if len(tournaments) == 0 {
        return nil
    }

    result := []TournamentGroup{
        {
            Year:        tournaments[0].Date.Year(),
            Tournaments: make([]Tournament, 0, 1),
        },
    }

    i := 0
    for _, tournament := range tournaments {
        year := tournament.Date.Year()
        if result[i].Year == year {
            // Add to existing group
            result[i].Tournaments = append(result[i].Tournaments, tournament)
        } else {
            // New group
            result = append(result, TournamentGroup{
                Year: year,
                Tournaments: []Tournament{
                    tournament,
                },
            })
            i++
        }
    }

    return result
}

func main() {
    tournaments := []Tournament{
        // for clarity - date is sorted, we don't need sort it again
        {"Town1", time.Date(2015, time.November, 10, 23, 0, 0, 0, time.Local)},
        {"Town2", time.Date(2015, time.October, 10, 23, 0, 0, 0, time.Local)},
        {"Town3", time.Date(2014, time.November, 10, 23, 0, 0, 0, time.Local)},
    }

    t, err := template.New("").Parse(`
{{$prev_year:=0}}
{{range .}}
    Actions in year {{.Year}}:
    {{range .Tournaments}}

            {{.Place}}, {{.Date}}
    {{end}}
    {{end}}

    `)
    if err != nil {
        panic(err)
    }
    err = t.Execute(os.Stdout, groupTournamentsByYear(tournaments))
    if err != nil {
        fmt.Println("executing template:", err)
    }
}

回答所述,该变量 "re-assignment" 的范围以 {{end}} 块结束。因此,仅使用标准变量 无法解决这个问题,应该在执行模板的 Go 程序中解决。

然而在某些框架中这并不容易(例如 protoc-gen-gotemplate)。

Sprig library 为标准模板语言添加了额外的功能。其中之一是可变映射,可以按以下方式使用:

// init the dictionary (you can init it without initial key/values as well)
{{$myVar := dict "key" "value"}}

// getting the "key" from the dictionary (returns array) and then fetching the first element from that array
{{pluck "key" $myVar | first}}

// conditional update block
{{if eq "some" "some"}}
     // the $_ seems necessary because Go template functions need to return something
     {{$_ := set $myVar "key" "newValue"}}
{{end}}

// print out the updated value
{{pluck "key" $myVar | first}}

这个小例子打印出来:

value
newValue

一种实用的方法是对所有可变变量使用单个字典,并将它们作为键存储在相应的变量名下。

参考:

在go1.11中text/template and hence html/template became able to set the value of existing variables,这意味着原始代码可以通过非常小的修改来工作。

改变

{{$prev_year:=$year}}

{{$prev_year = $year}}

Playground