文本/模板如何确定"默认文本表示"地图?

时间:2016-07-22 05:32:21

标签: string dictionary go go-templates go-html-template

根据Go标准库中text/template包的documentation,(据我所知,html/template在这里会是相同的)只需使用管道运算符就会吐出一个"默认文字表示"无论是什么:

  

{{管道}}

The default textual representation of the value of the pipeline is copied to the output.

对于地图,你会得到一个带有键名和所有内容的精美打印格式......顺便说一句,这是有效的JavaScript,所以如果你愿意,它可以很容易地将整个结构传递给你的JS代码。

我的问题是,这个文本表示是如何确定的,更具体地说,我可以加入它吗?我想也许它会检查管道是否是fmt.Stringer,我可以给我的地图子类型String() string方法,但似乎并非如此。我正在寻找text/template代码,但我似乎不知道它是如何做到的。

text/template如何确定"默认文字表示"?

1 个答案:

答案 0 :(得分:3)

确定默认文本表示形式fmt包如何打印该值。所以你在咆哮着树。

见这个例子:

t := template.Must(template.New("").Parse("{{.}}"))
m := map[string]interface{}{"a": "abc", "b": 2}
t.Execute(os.Stdout, m)

输出:

map[a:abc b:2]

现在,如果我们使用带有String()方法的自定义地图类型:

type MyMap map[string]interface{}

func (m MyMap) String() string { return "custom" }

mm := MyMap{"a": "abc", "b": 2}
t.Execute(os.Stdout, mm)

输出是:

custom

Go Playground上尝试这些(及以下示例)。

需要注意什么?

请注意MyMap.String()有一个值接收器(不是指针)。我传递了MyMap的值,所以它有效。如果将接收器类型更改为指向MyMap的指针,则无法正常工作。这是因为只有*MyMap类型的值才会有String()方法,而不是MyMap的值。

如果String()方法有指针接收器,则必须传递&mm(类型为*MyMap的值),如果您希望自定义表示工作。

另请注意,如果html/template,模板引擎会执行上下文转义,因此fmt包的结果可能会被进一步转义。

例如,如果您的自定义String()方法会返回某些内容"不安全":

func (m MyMap2) String() string { return "<html>" }

尝试插入它:

mm2 := MyMap2{"a": "abc", "b": 2}
t.Execute(os.Stdout, mm2)

获取转义:

&lt;html&gt;

实施

这是text/template包中实现的地方:text/template/exec.go,未导出的函数state.PrintValue(),当前行#848:

_, err := fmt.Fprint(s.wr, iface)

如果您正在使用html/template套餐,则会在html/template/content.go,未导出的功能stringify()中实施,目前为#135行

return fmt.Sprint(args...), contentTypePlain

更多选项

另请注意,如果值实现error,则会调用Error()方法,并且它优先于String()

type MyMap map[string]interface{}

func (m MyMap) Error() string { return "custom-error" }

func (m MyMap) String() string { return "custom" }

t := template.Must(template.New("").Parse("{{.}}"))
mm := MyMap{"a": "abc", "b": 2}
t.Execute(os.Stdout, mm)

将输出:

custom-error

而不是custom。在Go Playground上尝试。