dongyuan9149 2015-02-23 12:48
浏览 243
已采纳

在Go模板范围循环中,每次循环都会在循环外部声明的变量重置吗?

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?

  • 写回答

2条回答 默认 最新

  • dsdfd2322 2015-02-23 13:19
    关注

    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}}
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler
  • ¥15 关于#python#的问题:自动化测试