doudeng5764 2018-02-16 19:04
浏览 65
已采纳

是否可以在模板内部的结构内合理地呈现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.)

  • 写回答

2条回答 默认 最新

  • dongqing220586 2018-02-17 04:23
    关注

    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")
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 删除虚拟显示器驱动 删除所有 Xorg 配置文件 删除显示器缓存文件 重启系统 可是依旧无法退出虚拟显示器
  • ¥15 vscode程序一直报同样的错,如何解决?
  • ¥15 关于使用unity中遇到的问题
  • ¥15 开放世界如何写线性关卡的用例(类似原神)
  • ¥15 关于并联谐振电磁感应加热
  • ¥15 this signal is connected to multiple drivers怎么解决
  • ¥60 请查询全国几个煤炭大省近十年的煤炭铁路及公路的货物周转量
  • ¥15 请帮我看看我这道c语言题到底漏了哪种情况吧!
  • ¥66 如何制作支付宝扫码跳转到发红包界面
  • ¥15 pnpm 下载element-plus