是否可以在模板内的结构中合理地呈现url.URL值?

时间:2018-02-16 19:04:56

标签: go

我有一个结构,其url.URL 是其(多个)字段之一。我正在尝试将该结构的实例传递给html/template并让它以合理的方式呈现这些字段,包括URL。

考虑这个示例代码:

package main

import (
    "html/template"
    "net/url"
    "os"
)

var tmpl *template.Template = template.Must(
    template.New("").Parse(`<a href="{{ .URL }}">{{ .Text }}</a>` + "\n"),
)

type pointer struct {
    Text string
    URL  *url.URL // pointer, which is rendered sensibly
}

type value struct {
    Text string
    URL  url.URL // value, which is not rendered sensibly
}

func main() {
    u := url.URL{Scheme: "https", Host: "google.com", Path: "/path"}
    pointer := pointer{Text: "pointer", URL: &u}
    value := value{Text: "value", URL: u}

    tmpl.Execute(os.Stdout, pointer)
    tmpl.Execute(os.Stdout, value)
}

在我的机器上(去1.9.1),输出:

<a href="https://google.com/path">pointer</a>
<a href="%7bhttps%20%20%3cnil%3e%20google.com%20/path%20%20false%20%20%7d">value</a>

the playground上,输出:

<a href="https://google.com/path">pointer</a>
<a href="
** Signal 11 from untrusted code: pc=630b0008b020

Program exited.

html/template呈现url.URL 的最佳方式是什么?这是传递结构“通常”的字段?

(理想情况下,我只会更改模板,或者可能在FuncMap中使用某些内容。我还希望避免创建一堆几乎相同的结构{{1} } s而不是*url.URL s,或者必须使用struct的字段填充地图并将 传递给模板。)

2 个答案:

答案 0 :(得分:3)

问题是模板引擎不会使用值的地址来查找String() string方法。

一种解决方法是使用FuncMap:

func urlstr(u url.URL) string {
    return u.String()
}

var tmpl *template.Template = template.Must(
    template.New("").Funcs(template.FuncMap{"urlstr": urlstr}).Parse(`<a href="{{urlstr .URL}}">{{ .Text }}</a>` + "\n"),
)

请注意,在调用u时,编译器会隐式使用String() string的地址。

如果您混合使用*url.URLurl.URL值,并且不想担心模板中包含哪种类型,请将上面的函数urlstr替换为:< / p>

func urlstr(u interface{}) string {
    switch u := u.(type) {
    case *url.URL:
        return u.String()
    case url.URL:
        return u.String()
    default:
        panic("unexpected")
    }
}

答案 1 :(得分:-1)

看起来像带有url.URL值的func的FuncMap会这样做:

func f(u url.URL) string {
    return fmt.Sprintf("%s-%s-%s", u.Scheme, u.Host, u.Path)
}

funcMap := template.FuncMap{
    "url": f,
}

var tmpl *template.Template = template.Must(
    template.New("").Funcs(funcMap).Parse(`<a href="{{ url .URL }}">{{ .Text }}</a>` + "\n"),
)

为ptr和值产生相同的结果:

<a href="https-google.com-/path">pointer</a>
<a href="https-google.com-/path">value</a>

游乐场:https://play.golang.org/p/DMTFF3fueau

有趣的是,如果f占用ptr,它就会以同样的方式失败。