Golang新手请教:关于text/template的两个问题
Golang新手请教:关于text/template的两个问题 大家好,
我是Go语言的新手,如有不当之处还请见谅。我在网上看了一些示例,但遇到了一些我不理解的地方。
我将在此粘贴代码,以及之后的结果:
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.
我的两个问题:
- 如何使用 text/template 将浮点数值打印为两位小数?我想这在文档的某个地方有说明,但我还没有看到。
- 你可以看到,当我直接打印 sweaters 结构体时,它显示 19.2,但使用 text/template 时却显示为 19.25。通过反复试验,我发现它从 shoes 结构体中获取了第二位小数。我的问题是,它为什么要这样做?我知道这不是编写此代码的最佳方式,我应该将其放入循环中,但有趣的是,第二位小数竟然被改变了。
非常感谢。
更多关于Golang新手请教:关于text/template的两个问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
19.20 等于 19.2。尾随的零会被省略,除非你使用 printf 指令明确要求保留它们。
更多关于Golang新手请教:关于text/template的两个问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你好,@MrJohn,
你可以在 text/template 中使用 printf 函数,它提供了类似于 fmt 包中的格式化指令:
{{printf "%9.2f" .Price}}
问题在于你的两个模板之间没有换行符分隔,所以它打印出来的是:
"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"
你好,肖恩,
感谢你的 printf 解释。我完全理解了。
我理解你关于模板行的回复,但对我来说,仍然感到好奇的是,只有模板“占位符”的一部分被覆盖了。如果 Price 的全部内容都被覆盖,或者完全没有被覆盖,这对我来说是合理的。但偏偏只有一个数字被覆盖了。根据我所看到的,我推测 0 被移除了,所以毛衣的 Price 值是 19.2 而不是 19.20。然而……如果我将值设置为 19.21,我看到打印出来的是 19.215,这就更奇怪了。对此有什么想法吗?
如前所述,我知道这不是编写这个示例的最佳方式。例如,我会将其放入一个循环中,以便独立处理毛衣和鞋子。
非常感谢你的快速回复。
非常感谢,Sean。
我现在已经修改了代码,让模板在循环中运行,并使用printf来格式化价格。它的运行结果符合我的预期:
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)
}
}
}
针对你的两个问题,这里提供具体的解决方案和解释:
问题1:格式化浮点数为两位小数
使用printf函数进行格式化:
tmpl, err := template.New("test").Parse("{{.Count}} items of {{.Material}}, price {{printf \"%.2f\" .Price}}")
完整示例:
package main
import (
"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 {{printf \"%.2f\" .Price}}")
if err != nil {
panic(err)
}
tmpl.Execute(os.Stdout, sweaters)
os.Stdout.WriteString("\n")
tmpl.Execute(os.Stdout, shoes)
}
输出:
17 items of wool, price 19.20
5 items of leather, price 11.35
问题2:浮点数精度问题的原因
这个问题是由于text/template在执行时重用缓冲区导致的。当你连续调用Execute时,模板引擎会复用内部缓冲区,而浮点数转换可能没有完全清除之前的残留数据。
解决方案是每次执行后重置输出或使用不同的方式处理输出:
package main
import (
"bytes"
"fmt"
"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 {
panic(err)
}
// 使用独立的缓冲区
var buf1 bytes.Buffer
tmpl.Execute(&buf1, sweaters)
fmt.Println(buf1.String())
var buf2 bytes.Buffer
tmpl.Execute(&buf2, shoes)
fmt.Println(buf2.String())
}
或者使用循环并确保每次都有换行分隔:
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}}\n")
if err != nil {
panic(err)
}
items := []Inventory{sweaters, shoes}
for _, item := range items {
tmpl.Execute(os.Stdout, item)
}
}
这样就能确保每个输出都是独立的,避免缓冲区复用导致的精度问题。

