简体   繁体   English

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

[英]How does text/template determine the “default textual representation” of a map?

Per the documentation of the text/template package in the Go standard library, ( html/template would be the same here as far as I know) simply using the pipeline operator will spit out a "default textual representation" of whatever that is: 根据Go标准库中的text/template包的文档 ,(据我所知, html/template在这里是相同的)简单地使用管道操作符将吐出任何不同的“默认文本表示”:

{{pipeline}} {{管道}}

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

In the case of a map, you get a nice printed-out format with key names and everything...incidentally, this is valid JavaScript, so it makes it easy to pass whole structs into your JS code if you want. 在地图的情况下,你会得到一个很好的打印格式,其中包含键名和所有内容......顺便说一句,这是有效的JavaScript,因此如果你愿意,它可以很容易地将整个结构传递给你的JS代码。

My question is, how is this textual representation determined, and more specifically can I hook into it? 我的问题是,这个文本表示是如何确定的,更具体地说,我可以加入它吗? I thought perhaps it would check to see if the pipeline was a fmt.Stringer and I could give my map subtype a String() string method, but that doesn't seem to be the case. 我想也许它会检查管道是否是fmt.Stringer ,我可以给我的map子类型一个String() string方法,但似乎并非如此。 I'm hunting through the text/template code but I seem to be missing how it does this. 我正在寻找text/template代码,但我似乎不知道它是如何做到的。

How does text/template determine "default textual representation"? text/template如何确定“默认文本表示”?

The default textual representation is determined by how the fmt package prints the value. 默认文本表示由fmt包打印值的方式决定。 So you were barking up the right tree. 所以你正在吠叫正确的树。

See this example: 看这个例子:

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

It outputs: 它输出:

map[a:abc b:2]

Now if we use a custom map type with a String() method: 现在,如果我们使用带有String()方法的自定义地图类型:

type MyMap map[string]interface{}

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

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

Output is: 输出是:

custom

Try these (and below examples) on the Go Playground . Go Playground上试试这些(及以下示例)。

What to look out for? 需要注意什么?

Note that MyMap.String() has a value receiver (not a pointer). 请注意, MyMap.String()有一个值接收器(不是指针)。 And I pass a value of MyMap , so it works. 我传递了MyMap的值,所以它有效。 If you change the receiver type to pointer to MyMap , it won't work. 如果将接收器类型更改为指向MyMap指针,则它将不起作用。 And it is because then only a value of type *MyMap will have a String() method, but not a value of MyMap . 这是因为只有*MyMap类型的值才会有String()方法,而不是MyMap的值。

If the String() method has a pointer receiver, you have to pass &mm (a value of type *MyMap ) if you want your custom representation to work. 如果String()方法有一个指针接收器,如果希望自定义表示工作,则必须传递&mm (类型为*MyMap的值)。

Also note that in case of html/template , the template engine does contextual escaping, so the result of the fmt package may further be escaped. 另请注意,在html/template情况下,模板引擎执行上下文转义,因此fmt包的结果可能会被进一步转义。

For example if your custom String() method would return something "unsafe": 例如,如果您的自定义String()方法将返回“不安全”的内容:

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

Trying to insert it: 试图插入它:

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

Gets escaped: 获取转义:

&lt;html&gt;

Implementation 履行

This is where it is implemented in the text/template package: text/template/exec.go , unexported function state.PrintValue() , currently line #848: 这是在text/template包中实现的地方: text/template/exec.go ,unexported function state.PrintValue() ,当前行#848:

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

If you're using the html/template package, it's implemented in html/template/content.go , unexported function stringify() , currently line #135: 如果你正在使用html/template包,它是用html/template/content.go ,未实现的函数stringify() ,当前第135行:

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

Further options 更多选择

Also note that if the value implements error , the Error() method will be called and it takes precedence over String() : 另请注意,如果值实现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)

Will output: 将输出:

custom-error

Instead of custom . 而不是custom Try it on the Go Playground . Go Playground尝试一下。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM