Go テンプレートは、複雑なロジックをサポートするようには設計されていません。そのための Go プログラミング言語があります。この哲学の結果として、テンプレートには制限があります。制限の 1 つは、テンプレート変数を変更できないことです。
この制限に対処する 1 つの方法は、出力の構造に一致するように Go でデータを構造化することです。日付の投稿を保持するタイプを作成し、これらのタイプのスライスをレンダリングします。テンプレートは単純に PostsForDate と Posts の範囲です。
type PostsForDate struct {
Date time.Time
Posts []*Post
}
var Dates []PostsForDate
{{range .Dates}}
<div class="post-date">Posts dated: {{.Date}}</div>
{{range .Posts}}
<div class="post-content">{{.Content}}</div>
{{end}}
{{end}}
より単純なオプション (設計哲学にある程度反する) は、Go で型を作成して現在の値を記録し、その値への変更を報告することです。
type change struct {
current interface{}
}
func (c *change) Changed(next interface{}) bool {
result := c.current != next
c.current = next
return result
}
func newChange() *change {
return &change{&struct{ int }{}} // initial value ensures that first change is fired.
}
テンプレート関数を使用してテンプレートにフックします。
t := template.Must(template.New("").Funcs(template.FuncMap{"change": newChange}).Parse(` some template `))
次のようなテンプレートで使用します。
{{ $i := change }}
{{ range $post := .Posts }}
{{ $i.Change $post.Date }}
<div class="post-date">Posts dated: {{ $post.Date }}</div>
{{ end }}
<div class="post-content">{{ $post.Content }}</div>
{{ end }}
遊び場の例
投稿Date
フィールドが atime.Time
で、投稿が 1 日の中で異なる時間である場合、上記は期待どおりに機能しません。これを回避するには、レンダリングされた日付の変更を確認します (例: $post.Date.Format "2006-01-02"
)。これを簡素化するために、次のメソッドを追加します。
func (c *change) ChangedValue(next interface{}) interface{} {
if c.current != next {
c.current = next
return next
}
return nil
}
次のように使用します。
{{ $i := change }}
{{ range $post := .Posts }}
{{with $i.ChangedValue ($post.Date.Format "2006-01-02")}}
<div class="post-date">Posts dated: {{.}}</div>
{{ end }}
<div class="post-content">{{ $post.Content }}</div>
{{ end }}
これは、値がテンプレート パッケージによって true と見なされることが保証されている場合にのみ機能します。
このソリューションでは、使用するたびにテンプレートを解析する必要はなく (他の回答のソリューション #1 のように)、任意のスライス タイプに適用されます (他の回答の両方のソリューションとは異なります)。