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

I have a struct that has a url.URL value as one of its (many) fields. I'm trying to pass an instance of that struct to an html/template and have it render those fields, including the URL, in a sensible way.

Consider this example code:

package main

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

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

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)
}

On my machine (go 1.9.1), this outputs:

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

On the playground, this outputs:

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

Program exited.

What's the best way to have html/template render a url.URL value that's a field of a passed-struct “normally”?

(Ideally I'd only change the template, or possibly use something in a FuncMap. I'd also ideally like to avoid either having to create a bunch of almost-identical structs that have *url.URLs instead of url.URLs, or having to fill a map with the struct's fields and pass that to the template.)

The issue is that the template engine will not take the address of a value to find a String() string method.

One workaround is to use a 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>` + "
"),
)

Note that the complier implicitly takes the address of u when calling String() string.

If you have a mix of *url.URL and url.URL values and don't want to worry about which kind you have in the template, then replace the function urlstr above with:

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

Looks like a FuncMap with a func taking a url.URL value will do it:

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

and

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

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

produces the same result for both ptr and value:

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

Playground: https://play.golang.org/p/DMTFF3fueau

Interestingly, if f takes a ptr, it fails in the same way.