Go alternative for python loop.last

2.2k views Asked by At

I'm looking to loop over an array with Go templates and I want to add an extra string to the last item in the loop.

In python, I can do

{% for host in hosts %}
{{ host }}{% if loop.last %} ;{% endif %}
{% endfor %}

Looking to achieve same thing with Go, below is the snippet of the Go equivalent.

{{ range $host := $hosts }}
{{$host}}
{{ end }}

Thanks.

2

There are 2 answers

0
Cerise Limón On BEST ANSWER

If the list is not empty, then the Python snippet prints a semicolon following the last item. You can achieve the same result in Go by surrounding the range with an if to check to see if there's at least one element in the slice and printing the ; outside of the loop.

{{if $hosts}}{{range $host := $hosts}}
{{$host}}
{{ end }} ;{{end}}

This snippet works because you are adding to the end of the last item. A more general solution requires a custom template function. Here's an example function:

func last(v interface{}, i int) (bool, error) {
  rv := reflect.ValueOf(v)
  if rv.Kind() != reflect.Slice {
    return false, errors.New("not a slice")
  }
  return rv.Len()-1 == i, nil
}

and here's how to use it in the template:

{{range $i, $host := $hosts }}
{{$host}}{{if last $hosts $i}} ;{{end}}
{{ end }}

I posted an a working example of the custom function to the playground.

0
Joe Abbate On

An alternative is to define a decrement function, e.g.,

    "dec": func(n int) int { return n - 1 },

You can then use the dec function to calculate the last element, e.g.,

{{$last := dec (len $hosts)}}
{{range $i, $host := $hosts}}
{{$host}}{{if eq $i $last}} ;{{end}}
{{end}}

Of course, it would be easier if Go templates allowed subtraction so you could write {{$last := (len $hosts) - 1}}. After all, they insist on having a space before or after a spacing minus sign, so why not allow simple arithmetic?