我正在尝试使用在Go模板范围循环外声明的变量来查看上一篇文章是否与当前文章同一天发生。 这是一个简单的例子。
.Posts是一个post结构数组,每个数组都有一个.Content和一个.Date 。
{{ $prevDate := "" }} {{ range $post := .Posts }} {{ if ne $prevDate $post.Date }} <div class="post-date">Posts dated: {{ $post.Date }}</div> {{ end }} <div class="post-content">{{ $post.Content }}</div> {{ $prevDate := $post.Date }} {{ end }}问题在于$prevDate似乎在循环的每次迭代开始时重置为"" 。
任何人都可以帮助我理解为什么$prevDate的值在每次迭代时都被重置,并且可能提出了一种方法来实现我在此尝试做的事情?
I'm trying to use a variable declared outside a Go template range loop to see if the previous post occurred on the same day as the current post. Here's a simplified example.
Where .Posts is an array of post structs that each have a .Content and a .Date.
{{ $prevDate := "" }} {{ range $post := .Posts }} {{ if ne $prevDate $post.Date }} <div class="post-date">Posts dated: {{ $post.Date }}</div> {{ end }} <div class="post-content">{{ $post.Content }}</div> {{ $prevDate := $post.Date }} {{ end }}The problem is that $prevDate seems to be reset to "" at the start of each iteration of the loop.
Can anyone help me understand why the value of $prevDate is reset on each iteration and perhaps suggest a way to accomplish what I'm trying to do here?
最满意答案
变量不会重置。 基本上会发生什么是你重新声明循环内的$prevDate变量。 但仅在重新声明之后和{{range}}的结束{{end}}标记之前。 所以当循环的下一个迭代到来时,你只能看到你没有改变的“外部”变量(因为你创建了一个新的变量)。
您不能更改您创建的模板变量的值。
你可以做的是例如使用下面的range形式:
{{ range $index, $post := .Posts }}和...
解决方案#1:具有注册的功能
你可以为模板注册一个函数(参见template.Funcs() ),它可以传递$index ,它将返回前一个元素的日期字段(在$index -1 )。
它看起来像这样:
func PrevDate(i int) string { if i == 0 { return "" } return posts[i-1].Date } // Registering it: var yourTempl = template.Must(template.New(""). Funcs(map[string]interface{}{"PrevDate": PrevDate}). Parse(yourStringTemplate))从你的模板你可以这样称呼它:
{{range $index, $post := .Posts}} {{$prevDate := PrevDate $index}} {{end}}解决方案#2:使用帖子方法
这个解决方案是模拟的,但更简单:在你的Posts添加一个方法,你可以直接调用它。 无需注册功能。
例如:
type Post struct { // Your Post type Date string } type Posts []Post func (p *Posts) PrevDate(i int) string { if i == 0 { return "" } return (*p)[i-1].Date }从你的模板你可以这样称呼它:
{{range $index, $post := .Posts}} {{$prevDate := $.Posts.PrevDate $index}} {{end}}Note: Go 1.11 will support modifying template variables via assignment. This will be valid code:
{{ $v := "init" }} {{ if true }} {{ $v = "changed" }} {{ end }} v: {{ $v }} {{/* "changed" */}}Original answer pre-dating Go 1.11 follows:
Variables are not reset. Basically what happens is that you redeclare the $prevDate variable inside the loop. But it is only in scope after the redeclaration and before the closing {{end}} tag of the {{range}}. So when the next iteraiton of the loop comes, you only see the "outer" variable which you haven't changed (because you created a new).
You can't change the values of the template variables you create.
What you can do is for example use the following range form:
{{ range $index, $post := .Posts }}And...
Solution #1: with a registered Function
And you can register a function for the template (see template.Funcs()) to which you can pass the $index and it would return the date field of the previous element (at $index -1).
It would look something like this:
func PrevDate(i int) string { if i == 0 { return "" } return posts[i-1].Date } // Registering it: var yourTempl = template.Must(template.New(""). Funcs(map[string]interface{}{"PrevDate": PrevDate}). Parse(yourStringTemplate))And from your template you can call it like:
{{range $index, $post := .Posts}} {{$prevDate := PrevDate $index}} {{end}}Solution #2: with a Method of Posts
This solution is analog but is even simpler: add a method to your Posts and you can call it directly. No need to register a function.
For example:
type Post struct { // Your Post type Date string } type Posts []Post func (p *Posts) PrevDate(i int) string { if i == 0 { return "" } return (*p)[i-1].Date }And from your template you can call it like:
{{range $index, $post := .Posts}} {{$prevDate := $.Posts.PrevDate $index}} {{end}}更多推荐
发布评论