根据 documentation Go 标准库中的 text/template
包,(据我所知,html/template
在这里是相同的)简单地使用管道运算符会吐出一个任何内容的“默认文本表示”:
{{pipeline}}
The default textual representation of the value of the pipeline is copied to the output.
对于 map ,您会得到一个很好的打印输出格式,其中包含键名称和所有内容...顺便说一句,这是有效的 JavaScript,因此如果需要,可以轻松地将整个结构传递到 JS 代码中。
我的问题是,这个文本表示是如何确定的,更具体地说,我可以连接它吗?我想也许它会检查管道是否是一个 fmt.Stringer
并且我可以给我的 map 子类型一个 String() string
方法,但这似乎不是是这样的。我正在寻找 text/template
代码,但我似乎不知道它是如何做到这一点的。
text/template
如何确定“默认文本表示”?
最佳答案
默认的文本表示是由 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()
方法的自定义 map 类型:
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)
逃脱:
<html>
实现
这是在 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
而不是自定义
。试试 Go Playground .
关于string - 文本/模板如何确定 map 的 "default textual representation"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38518866/