默认文本表示由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
,它将不起作用。这是因为只有 type 的值*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
而不是custom
. 在Go Playground上尝试一下。