doudu5498 2016-07-22 05:32
浏览 31
已采纳

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

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:

{{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.

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. I'm hunting through the text/template code but I seem to be missing how it does this.

How does text/template determine "default textual representation"?

  • 写回答

1条回答 默认 最新

  • dongsuishou8039 2016-07-22 06:57
    关注

    The default textual representation is determined by how the fmt package prints the value. 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:

    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.

    What to look out for?

    Note that MyMap.String() has a value receiver (not a pointer). And I pass a value of MyMap, so it works. If you change the receiver type to pointer to MyMap, it won't work. And it is because then only a value of type *MyMap will have a String() method, but not a value of 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.

    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.

    For example if your custom String() method would return something "unsafe":

    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:

    _, 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:

    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():

    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. Try it on the Go Playground.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 永磁型步进电机PID算法
  • ¥15 sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?
  • ¥88 找成都本地经验丰富懂小程序开发的技术大咖
  • ¥15 如何处理复杂数据表格的除法运算
  • ¥15 如何用stc8h1k08的片子做485数据透传的功能?(关键词-串口)
  • ¥15 有兄弟姐妹会用word插图功能制作类似citespace的图片吗?
  • ¥200 uniapp长期运行卡死问题解决
  • ¥15 latex怎么处理论文引理引用参考文献
  • ¥15 请教:如何用postman调用本地虚拟机区块链接上的合约?
  • ¥15 为什么使用javacv转封装rtsp为rtmp时出现如下问题:[h264 @ 000000004faf7500]no frame?