text/template如何确定地图的"default textual representation"?
How does text/template determine the "default textual representation" of a map?
根据 Go 标准库中 text/template
包的 documentation,(据我所知,html/template
在这里是一样的)简单地使用管道运算符会吐输出一个 "default textual representation" 的任何东西:
{{pipeline}}
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
如何确定"default textual representation"?
默认文本表示由 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
上尝试这些(以及以下示例)
需要注意什么?
注意 MyMap.String()
有一个值接收者(不是指针)。我传递了一个 MyMap
的值,所以它起作用了。如果将接收器类型更改为指向 MyMap
的指针,它将不起作用。这是因为只有 *MyMap
类型的值才会有 String()
方法,而不是 MyMap
.
类型的值
如果 String()
方法有一个指针接收器,如果您希望自定义表示起作用,则必须传递 &mm
(类型 *MyMap
的值)。
另请注意,在 html/template
的情况下,模板引擎会进行上下文转义,因此 fmt
包的结果可能会进一步转义。
例如,如果您的自定义 String()
方法会 return 一些“不安全”的东西:
func (m MyMap2) String() string { return "<html>" }
正在尝试插入:
mm2 := MyMap2{"a": "abc", "b": 2}
t.Execute(os.Stdout, mm2)
被转义:
<html>
实施
这是它在 text/template
package: text/template/exec.go
中实现的地方,未导出的函数 state.PrintValue()
,当前行 #848:
_, err := fmt.Fprint(s.wr, iface)
如果您正在使用 html/template
package, it's implemented in 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.
上试用
根据 Go 标准库中 text/template
包的 documentation,(据我所知,html/template
在这里是一样的)简单地使用管道运算符会吐输出一个 "default textual representation" 的任何东西:
{{pipeline}}
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
如何确定"default textual representation"?
默认文本表示由 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
上尝试这些(以及以下示例)
需要注意什么?
注意 MyMap.String()
有一个值接收者(不是指针)。我传递了一个 MyMap
的值,所以它起作用了。如果将接收器类型更改为指向 MyMap
的指针,它将不起作用。这是因为只有 *MyMap
类型的值才会有 String()
方法,而不是 MyMap
.
如果 String()
方法有一个指针接收器,如果您希望自定义表示起作用,则必须传递 &mm
(类型 *MyMap
的值)。
另请注意,在 html/template
的情况下,模板引擎会进行上下文转义,因此 fmt
包的结果可能会进一步转义。
例如,如果您的自定义 String()
方法会 return 一些“不安全”的东西:
func (m MyMap2) String() string { return "<html>" }
正在尝试插入:
mm2 := MyMap2{"a": "abc", "b": 2}
t.Execute(os.Stdout, mm2)
被转义:
<html>
实施
这是它在 text/template
package: text/template/exec.go
中实现的地方,未导出的函数 state.PrintValue()
,当前行 #848:
_, err := fmt.Fprint(s.wr, iface)
如果您正在使用 html/template
package, it's implemented in 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.