【问题标题】:Go template remove the last comma in range loopGo模板删除范围循环中的最后一个逗号
【发布时间】:2017-03-08 03:37:43
【问题描述】:

我有这样的代码:

package main

import (
    "text/template"
    "os"
)

func main() {
    type Map map[string]string
    m := Map {
        "a": "b",
        "c": "d",
    }
    const temp = `{{range $key, $value := $}}key:{{$key}} value:{{$value}},{{end}}`
    t := template.Must(template.New("example").Parse(temp))
    t.Execute(os.Stdout, m)
}

它会输出:

key:a 值:b,key:c 值:d,

但我想要这样的东西:

key:a 值:b,key:c 值:d

我不需要最后一个逗号,如何删除它。我在这里找到了循环数组的解决方案:https://groups.google.com/d/msg/golang-nuts/XBScetK-guk/Bh7ZFz6R3wQJ,但我无法获取地图的索引。

【问题讨论】:

  • 在模板中可撤销。您必须直接在您的 Go 代码中执行此操作,或者将 TrimTrailingComma 之类的函数公开给您的模板。
  • 谢谢,我会想办法解决的
  • 我认为可以通过这个问题/答案找到最优雅的解决方案:stackoverflow.com/questions/10747054/…
  • @jboschiero 优雅的解决方案适用于切片,不适用于地图。
  • @Volker 从 Go 1.11 开始就有可能。见answer below

标签: go go-templates


【解决方案1】:

自 Go 1.11 it is now possible to change values of template variables.这使我们可以在不需要自定义函数(在模板之外)的情况下执行此操作。

以下模板可以做到这一点:

{{$first := true}}
{{range $key, $value := $}}
    {{if $first}}
        {{$first = false}}
    {{else}}
        ,
    {{end}}
    key:{{$key}} value:{{$value}}
{{end}}

这是问题中修改后的工作示例:

type Map map[string]string
m := Map{
    "a": "b",
    "c": "d",
    "e": "f",
}
const temp = `{{$first := true}}{{range $key, $value := $}}{{if $first}}{{$first = false}}{{else}}, {{end}}key:{{$key}} value:{{$value}}{{end}}`
t := template.Must(template.New("example").Parse(temp))
t.Execute(os.Stdout, m)

哪些输出(在Go Playground 上试试):

key:a value:b, key:c value:d, key:e value:f

【讨论】:

  • 你知道我需要哪个版本的 Docker 才能工作吗?
  • 太棒了,当有嵌套循环时,这会大大简化。
【解决方案2】:

以下是使用模板函数编写逗号分隔键值对的方法。

声明一个函数,该函数返回一个递增并返回一个计数器的函数:

func counter() func() int {
    i := -1
    return func() int {
        i++
        return i
    }
}

将此函数添加到模板中:

t := template.Must(template.New("example").Funcs(template.FuncMap{"counter": counter}).Parse(temp))

像这样在模板中使用它:

    {{$c := counter}}{{range $key, $value := $}}{{if call $c}}, {{end}}key:{{$key}} value:{{$value}}{{end}}

此模板将分隔符写在键值对之前而不是在键值对之后。

计数器在循环之前创建,并在循环的每次迭代中递增。分隔符不是第一次通过循环写入的。

Run it in the playground.

模板中的逻辑可以通过将 if 语句移到 Go 代码中来简化:

func separator(s string) func() string {
    i := -1
    return func() string {
        i++
        if i == 0 {
            return ""
        }
        return s
    }
}

将函数添加到模板中:

t := template.Must(template.New("example").Funcs(template.FuncMap{"separator": separator}).Parse(temp))

像这样使用它:

{{$s := separator ", "}}{{range $key, $value := $}}{{call $s}}key:{{$key}} value:{{$value}}{{end}}

Run it on the playground.

【讨论】:

  • 正如@Volker 所说,无法在模板中执行此操作,也许这是最好的解决方案
【解决方案3】:

我使用下面的模板通过 go 模板正确格式化了一些 JSON。

它处理任何大小或空的集合。

{{- define "JoinList" -}}
   {{- $lastIndex := math.Sub (len .) 1 -}}
   {{- range $index, $property := . -}}
   {{ if isKind "string" $property.value }}
   "{{ $property.key }}": "{{ $property.value }}"{{ if ne $index $lastIndex }},{{ end }}
   {{- else -}}
   "{{ $property.key }}": {{ $property.value }}{{ if ne $index $lastIndex }},{{ end }}
   {{ end }}
   {{- end -}}
{{- end -}}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-05
    • 2018-02-14
    • 2020-01-24
    相关资源
    最近更新 更多