Шаблон Go удаляет последнюю запятую в цикле диапазона

У меня есть такой код:

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)
}

он выведет:

ключ:значение:b,ключ:c значение:d,

но я хочу что-то вроде этого:

ключ:a значение:b, ключ:c значение:d

Мне не нужна последняя запятая, как ее убрать. Я нашел решение для зацикливания массива здесь: https://groups.google.com/d/msg/golang-nuts/XBScetK-guk/Bh7ZFz6R3wQJ , но я не могу получить индекс карты.


person Chris    schedule 08.03.2017    source источник
comment
Отменяется в шаблонах. Вы должны сделать это либо непосредственно в своем коде Go, либо предоставить такую ​​функцию, как TrimTrailingComma, в свой шаблон.   -  person Volker    schedule 08.03.2017
comment
спасибо, я найду другой способ решить эту проблему   -  person Chris    schedule 08.03.2017
comment
Я думаю, что самое элегантное решение можно найти с помощью этого вопроса/ответа: stackoverflow.com/questions/10747054/   -  person j boschiero    schedule 14.11.2017
comment
@jboschiero Элегантное решение работает для срезов, а не для карт.   -  person Deleplace    schedule 18.01.2018
comment
@Volker Это возможно с Go 1.11. См. ответ ниже.   -  person icza    schedule 17.03.2019


Ответы (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}}

Этот шаблон записывает разделители перед парами ключ-значение, а не после пар.

Счетчик создается перед циклом и увеличивается на каждой итерации цикла. Разделитель не записывается при первом прохождении цикла.

Запустите его на игровой площадке.

Логику в шаблоне можно упростить, переместив оператор 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}}

Запустите его на игровой площадке.

person Cerise Limón    schedule 08.03.2017
comment
Как говорит @Volker, в шаблоне это сделать невозможно, возможно, это лучшее решение. - person Chris; 08.03.2017

Начиная с Go 1.11 теперь можно изменять значения переменных шаблона. Это дает нам возможность сделать это без необходимости использования пользовательской функции (находящейся вне шаблона).

Следующий шаблон делает это:

{{$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
person icza    schedule 17.03.2019
comment
Вы случайно не знаете, какая версия Docker мне нужна, чтобы он работал? - person x-yuri; 01.07.2019
comment
отлично, это многое упрощает, когда есть вложенные циклы. - person charli; 31.05.2020