New to golang, two queries about text/template

Greetings Gophers,

I am quite new to Go so forgive my ignorance. I have been looking at some examples on the net, but have run into something which I do not understand.

I will paste the code here, and the result afterwards:

package main

import (
	"fmt"
	"os"
	"text/template"
)

type Inventory struct {
	Material string
	Count    uint
	Price    float32
}

func main() {
	sweaters := Inventory{"wool", 17, 19.20}
	shoes := Inventory{"leather", 5, 11.35}

	tmpl, err := template.New("test").Parse("{{.Count}} items of {{.Material}}, price {{.Price}}")
	if err != nil {
		fmt.Println(err)
	}

	fmt.Println("Sweaters:", sweaters)
	fmt.Println("Shoes:", shoes)
	err = tmpl.Execute(os.Stdout, sweaters)
	if err != nil {
		fmt.Println(err)
	}
	err = tmpl.Execute(os.Stdout, shoes)
	if err != nil {
		fmt.Println(err)
	}
}

/usr/local/go/bin/go build [/Users/jre/go/src/jre/template1]
Success: process exited with code 0.
/Users/jre/go/src/jre/template1/template1 [/Users/jre/go/src/jre/template1]
Sweaters: {wool 17 19.2}
Shoes: {leather 5 11.35}
17 items of wool, price 19.25 items of leather, price 11.35Success: process exited with code 0.

My two queries:

  1. How does one ‘print’ a float value with two decimal places using text/template? I imagine this is in the docs somewhere, but I haven’t seen it yet.
  2. You can see when I directly print the sweaters struct it shoes 19.2, but when using text/template it shows as 19.25. I can see by trial and error that it is picking up the second decimal place from the shoes struct. My question is why is it doing that? I know this is not the best way to write this code, and I should put it into a loop, but it is interesting to me that the second decimal place has been altered at all.

Many thanks,
JRE.

Hi, @MrJohn,

You can use a printf function in text/template which gives you formatting directives like in the fmt package:

{{printf "%9.2f" .Price}} 

What’s happening is you don’t have a newline separating your two templates, so it’s printing:

"17 items of wool, price 19.2" + "5 items of leather, price 11.35" = "17 items of wool, price 19.25 items of leather, price 11.35"

Greetings Sean,

Thanks for the printf. Understood completely.

I understand your reply about the template line, but it’s still curious to me that only part of the template ‘placeholder’ has been overwritten. If all of Price was overwritten, or none of it, that would make sense to me. But just one number has been. I presumed from what I saw that the 0 is being removed so the value of Price for sweaters is 19.2 rather than 19.20. However… if I set the value to 19.21, I see that 19.215 is printed out, which is even more curious. Any ideas about that?

As mentioned, I know this is not the best way to write this example. I would put it into a loop, for example, to handle sweaters and shoes independently.

Many thanks for the quick reply.

JRE.

19.20 == 19.2. The trailing 0s are omitted unless you request them explicitly with the printf directive.

Many thanks, Sean.

I’ve changed the code now so the template runs in a loop, and using printf for the price. It works as I expected;

package main

import (
	"fmt"
	"os"
	"text/template"
)

type Inventory struct {
	Material string
	Count    uint
	Price    float32
}

func main() {
	sweaters := Inventory{"wool", 17, 19.21}
	shoes := Inventory{"leather", 5, 11.35}

	items := []Inventory{}
	items = append(items, sweaters)
	items = append(items, shoes)
	for _, item := range items {
		//fmt.Println(item)

		tmpl, err := template.New("test").Parse("{{.Count}} items of {{.Material}}, price {{printf \"%3.2f\" .Price}}\n")
		if err != nil {
			fmt.Println(err)
		}

		err = tmpl.Execute(os.Stdout, item)
		if err != nil {
			fmt.Println(err)
		}

	}
}


JRE.