Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go templates with eq and index

Go templates have some unexpected results when using eq with index for me. See this code:

package main

import (
    "os"
    "text/template"
)

func main() {
    const myTemplate = `
{{range $n := .}}
    {{index $n 0}} {{if (index $n 0) eq (index $n 1)}}={{else}}!={{end}} {{index $n 1}}
{{end}}
`
    t := template.Must(template.New("").Parse(myTemplate))

    t.Execute(os.Stdout,
        [][2]int{
            [2]int{1, 2},
            [2]int{2, 2},
            [2]int{4, 2},
        })

}

I expect to have output

1 != 2
2 = 2
4 != 2

but I get

1 = 2
2 = 2
4 = 2

What should I change to be able to compare array members in go templates?

like image 641
Ondra Avatar asked Oct 22 '15 13:10

Ondra


2 Answers

You use wrong operator and argument order. You have to first write the operator and then the operands:

{{if eq (index $n 0) (index $n 1)}}

This is more readable and handy as eq can take more than just 2 arguments, so you could write for example:

{{if eq (index $n 0) (index $n 1) (index $n 2)}}

For simpler multi-way equality tests, eq (only) accepts two or more arguments and compares the second and subsequent to the first, returning in effect

arg1==arg2 || arg1==arg3 || arg1==arg4 ...

(Unlike with || in Go, however, eq is a function call and all the arguments will be evaluated.)

With this change the output (try it on the Go Playground):

1 != 2

2 = 2

4 != 2

Note:

You are not required to introduce a "loop" variable, the {{range}} action changes the dot to the current item:

...dot is set to the successive elements of the array, slice, or map...

So you can simplify your template, this is equivalent to yours:

{{range .}}
    {{index . 0}} {{if eq (index . 0) (index . 1)}}={{else}}!={{end}} {{index . 1}}
{{end}}

Also note that you can create variables in the template yourself, which is recommended if you use the same expression multiple times which is nontrivial (such as index . 0). This is also equivalent to your template:

{{range .}}{{$0 := index . 0}}{{$1 := index . 1}}
    {{$0}} {{if eq $0 $1}}={{else}}!={{end}} {{$1}}
{{end}}

Also note that in this specific case since the things you want to output in the if and else branches both contain the = sign, you don't need 2 branches, = needs to be outputted in both cases, you just need an extra ! sign if they are not equal. So the following final template is also equivalent to yours:

{{range .}}{{$0 := index . 0}}{{$1 := index . 1}}
    {{$0}} {{if ne $0 $1}}!{{end}}= {{$1}}
{{end}}
like image 182
icza Avatar answered Nov 07 '22 04:11

icza


eq is a prefix operation:

{{if eq (index $n 0) (index $n 1)}}={{else}}!={{end}}

Playground: http://play.golang.org/p/KEfXH6s7N1.

like image 44
Ainar-G Avatar answered Nov 07 '22 05:11

Ainar-G