web-dev-qa-db-ja.com

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)
    }
}
12
lofcek

編集: https://stackoverflow.com/a/52925780/1685538 を参照して、最新の回答を入手してください。


元の回答:

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

変数のスコープは、変数が宣言されている制御構造(「if」、「with」、または「range」)の「end」アクション、またはそのような制御構造がない場合はテンプレートの最後まで拡張されます。

したがって、$prev_yearで定義する{{$prev_year:=$year}}は、次の行({{end}})までしか存続しません。

それを回避する方法はないようです。

これを行う「正しい」方法は、テンプレートからそのロジックを取り出し、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)
    }
}
12
HectorJ

Go1.11では text/template、したがってhtml/templateが既存の変数の値を設定できるようになりました は、元のコードを1つの非常に小さな修正で動作させることができることを意味します。

変化する

{{$prev_year:=$year}}

{{$prev_year = $year}}

プレイグラウンド

4
Nick Craig-Wood

this answerで述べたように、その変数「再割り当て」のスコープは{{end}}ブロック。したがって、標準変数onlyを使用すると、問題を回避する方法はなく、テンプレートを実行するGoプログラム内で解決する必要があります。

ただし、一部のフレームワークでは、これはそれほど簡単ではありません(例:protoc-gen-gotemplate)。

Sprigライブラリ は、標準テンプレート言語に追加機能を追加します。それらの1つは、次の方法で使用できる可変マップです。

// 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

実用的なアプローチは、すべての可変変数に単一の辞書を使用し、対応する変数名の下にキーとして保存することです。

参照:

2
Peter Ilfrich