douzhan6474 2013-09-10 21:01
浏览 30
已采纳

在Go文本模板中遍历地图

I have a map of values that looks like this:

vals := map[string]interface{}{"foo": 1, "bar": 2, "baz": 7}
data := map[string]interface{}{"bat": "obj", "values": vals}

What should my template look like to generate the following string (note the correct comma usage)?

SET obj.foo=1, obj.bar=2, obj.baz=7

I started with this as my template:

SET {{range $i, $v := .values}} {{.bat}}.{{$i}}={{$v}},{{end}}

But that just prints out

SET

And even if that did work, the commas would be incorrect. I then tried to use a custom function to format the map, but I couldn't get the template to ever call my function. None of the following seemed to work:

SET {{.MyFunction .values}}
SET {{call .MyFunction .values}}
SET {{call MyFunction .values}}

when MyFunction was defined as:

func MyFunction(data map[string]interface{}) string {
  fmt.PrintLn('i was called!')
  return "foo"
}

And I'm executing the templates using a helper function that looks like this:

func useTemplate(name string, data interface{}) string {
  out := new(bytes.Buffer)
  templates[name].Execute(out, data)
  return string(out.Bytes())
}

Thanks!

  • 写回答

1条回答 默认 最新

  • doutan2456 2013-09-10 22:19
    关注

    This will get you pretty close:

    SET {{range $key, $value := $.values}}{{$.bat}}.{{$key}}={{$value}} {{end}}
    

    rendering as:

    SET obj.bar=2 obj.baz=7 obj.foo=1
    

    Unfortunately, I don't think there's any simple way to have the commas added in between the values due to how the range action iterates on maps (there's no numeric index). That said, the template packages were meant to be easily extensible so you can have less logic in your templates and more logic in Go itself, so it's easy enough to code a helper function in Go and make it available to your templates.

    If you're happy to go that extra mile, then the template becomes much simpler, and also more efficient. The function can look like this:

    func commaJoin(prefix string, m map[string]interface{}) string {
        var buf bytes.Buffer
        first := true
        for k, v := range m {
            if !first {
                buf.WriteString(", ")
            }
            first = false
            buf.WriteString(prefix)
            buf.WriteByte('.')
            buf.WriteString(k)
            buf.WriteByte('=')
            buf.WriteString(fmt.Sprint(v))
        }
        return buf.String()
    }
    

    and your template would look like:

    SET {{$.values | commaJoin $.bat}}
    

    Here is a working example with this logic:

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 抖音咸鱼付款链接转码支付宝
  • ¥15 ubuntu22.04上安装ursim-3.15.8.106339遇到的问题
  • ¥15 求螺旋焊缝的图像处理
  • ¥15 blast算法(相关搜索:数据库)
  • ¥15 请问有人会紧聚焦相关的matlab知识嘛?
  • ¥15 网络通信安全解决方案
  • ¥50 yalmip+Gurobi
  • ¥20 win10修改放大文本以及缩放与布局后蓝屏无法正常进入桌面
  • ¥15 itunes恢复数据最后一步发生错误
  • ¥15 关于#windows#的问题:2024年5月15日的win11更新后资源管理器没有地址栏了顶部的地址栏和文件搜索都消失了