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://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)
}
}
Go1.11では text/template、したがってhtml/templateが既存の変数の値を設定できるようになりました は、元のコードを1つの非常に小さな修正で動作させることができることを意味します。
変化する
{{$prev_year:=$year}}
に
{{$prev_year = $year}}
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
実用的なアプローチは、すべての可変変数に単一の辞書を使用し、対応する変数名の下にキーとして保存することです。
参照: