Arithmetic in Go templates
Asked Answered
P

4

44

I am trying to achieve a very simple thing in a Go template and failing!

The range action allows me to iterate through an array along with its zero-based index, as so:

{{range $index, $element := .Pages}}
  Number: {{$index}}, Text: {{element}}
{{end}}

However, I am trying to output indices that start counting from 1. My first attempt failed:

Number: {{$index + 1}}

This throws an illegal number syntax: "+" error.

I looked into the go-lang official documentation and did not find anything particular regarding the arithmetic operation inside the template.

What am I missing?

Primaveras answered 5/9, 2014 at 15:59 Comment(0)
O
59

You have to write a custom function to do this.

http://play.golang.org/p/WsSakENaC3

package main

import (
    "os"
    "text/template"
)

func main() {
    funcMap := template.FuncMap{
        // The name "inc" is what the function will be called in the template text.
        "inc": func(i int) int {
            return i + 1
        },
    }

    var strs []string
    strs = append(strs, "test1")
    strs = append(strs, "test2")

    tmpl, err := template.New("test").Funcs(funcMap).Parse(`{{range $index, $element := .}}
  Number: {{inc $index}}, Text:{{$element}}
{{end}}`)
    if err != nil {
        panic(err)
    }
    err = tmpl.Execute(os.Stdout, strs)
    if err != nil {
        panic(err)
    }
}
Obtest answered 5/9, 2014 at 17:16 Comment(0)
A
21

If you happen to be writing a Go template for use in consul-template, you may find their exposed arithmetic functions useful:

Number: {{add $index 1}}
Anosmia answered 31/12, 2015 at 0:49 Comment(0)
H
10

Check the documentation about the built-in functions of text/template:

  • len can produce an integer from a string: {{ len "abc" }}
  • printf can produce a string of a given length from an integer: {{ printf "%*s" 3 "" }}
  • slice can truncate a string to a given length from an integer: {{ slice "abc" 0 2 }}
  • slice can truncate a string by a given length from an integer: {{ slice "abc" 1 }}

You can combine both to increment an integer:

{{ len (printf "a%*s" 3 "") }}

will produce:

4

Or to decrement an integer:

{{ len (slice (printf "%*s" 3 "") 1) }}

shows:

2

You can also define templates to reuse pieces of templates.

So we can define 1 argument functions with templates (see on the Go Playground):

{{ define "inc" }}{{ len (printf "%*s " . "") }}{{ end -}}
{{ define "op" }}{{.}} + 1 = {{ template "inc" . }}{{ end -}}
{{ template "op" 2 }}
{{ template "op" 5 }}

shows:

2 + 1 = 3
5 + 1 = 6

We can go further if the input of the template is an array of integers ([]int{4, 2, 7}):

{{ define "inc" }}{{ len (printf "%*s " . "") }}{{ end -}}
{{ define "op" }}{{.}} + 1 = {{ template "inc" . }}{{ end -}}
{{- range . -}}
{{ template "op" . }}
{{ end -}}

See full example on the Go Playground.

Holloweyed answered 1/6, 2022 at 16:17 Comment(3)
really nice hack for those unable to add a custom function, thank you!Slipstream
Beautiful, thank you for this insight! The box I think outside of clearly isn't big enough!Kipp
what if you want to sum 2 numbers? this will only increase by 1Risorgimento
D
2

There's also way to just make a HTML list, however that won't fit for all cases.

<ol>
{{range $index, $element := .Pages}}
  <li>Text: {{$element}}</li>
{{end}}
</ol>

And it can produce something like that

  1. Text: Some page
  2. Text: Some different page
Destalinization answered 2/2, 2021 at 15:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.