You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang模板嵌套循环中自定义计数器变量更新打印问题排查

问题原因
  • 上下文被覆盖:你使用{{with $i := 0}}声明变量时,with块会把当前作用域的.(上下文)直接替换为0这个整数值。后续你写的.Numbers、.Letters本质是尝试从整数0上获取对应字段,根本读不到你传入的data结构体,模板执行直接报错。
  • 版本兼容问题:Go 1.11版本之前的text/template库不支持对已声明变量做重新赋值(也就是{{$i = add $i 1}}这种写法不生效),即使是支持该语法的高版本,也需要避免上下文被覆盖的问题。
修复方案

方案1:高版本Go直接修复上下文

如果你使用Go 1.11及以上版本,只需要保留顶层根数据的引用,不使用with覆盖上下文即可正常运行:

var tmplSrc = `start
{{$root := .}}
{{$i := 0}}
{{range $number := $root.Numbers}}
  {{range $letter := $root.Letters}}
    {{if eq $letter "b"}}
      {{$i = add $i 1}}
      {{$i}}
    {{end}}
  {{end}}
{{end}}
fin
`

运行后会依次输出1 2 3 4,符合计数预期。

方案2:全版本兼容的引用类型计数器

如果需要兼容低版本Go,可以用引用类型(比如map)作为计数器,修改引用指向的内容不受模板作用域限制:

  1. 先在FuncMap中添加dict工具函数用于创建map(标准库模板默认没有内置该函数):
funcMap := template.FuncMap{
    "add": func(a int, b int) int {
        return a + b
    },
    "dict": func(values ...interface{}) (map[string]interface{}, error) {
        if len(values)%2 != 0 {
            return nil, errors.New("invalid dict call")
        }
        dict := make(map[string]interface{}, len(values)/2)
        for i := 0; i < len(values); i += 2 {
            key, ok := values[i].(string)
            if !ok {
                return nil, errors.New("dict keys must be strings")
            }
            dict[key] = values[i+1]
        }
        return dict, nil
    },
}
  1. 调整模板部分:
var tmplSrc = `start
{{$root := .}}
{{$counter := dict "val" 0}}
{{range $number := $root.Numbers}}
  {{range $letter := $root.Letters}}
    {{if eq $letter "b"}}
      {{$counter.val = add $counter.val 1}}
      {{$counter.val}}
    {{end}}
  {{end}}
{{end}}
fin
`

修改$counter.val本质是修改map内部的值,所有作用域都能读到更新后的数据。

内容的提问来源于stack exchange,提问作者Sam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 20:24:03