【问题标题】:Is it possible to sensibly render a url.URL value within a struct inside a template?是否可以在模板内的结构中合理地呈现 url.URL 值?
【发布时间】:2023-03-07 09:58:01
【问题描述】:

我有一个结构,它有一个 url.URL value 作为它的(许多)字段之一。我正在尝试将该结构的实例传递给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 中使用某些东西。理想情况下,我还希望避免创建一堆几乎相同的结构,这些结构具有*url.URLs 而不是url.URLs,或者必须用结构的字段填充映射并将 that 传递给模板。)

【问题讨论】:

  • play.golang.org/p/PtPNvQV9vNc 如果你想要一个函数同时用于两个函数,让它接受一个接口,然后输入 assert。
  • net.URL 的每个方法和构造函数都使用指针。为什么要使用值?
  • @Adrian:这些结构由数据库支持,所以看起来很合理,但你说得很好。

标签: go


【解决方案1】:

问题在于模板引擎不会通过值的地址来查找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"),
)

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

如果您混合了*url.URLurl.URL 值,并且不想担心模板中有哪一种,则将上面的函数urlstr 替换为:

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

【讨论】:

    【解决方案2】:

    看起来像带有 func 的 FuncMap 采用 url.URL 值会做到这一点:

    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 和 value 产生相同的结果:

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

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

    有趣的是,如果 f 接受一个 ptr,它会以同样的方式失败。

    【讨论】:

    • 这不会产生有效的 URL 作为输出。
    猜你喜欢
    • 2011-02-15
    • 2023-01-12
    • 1970-01-01
    • 2022-01-05
    • 2023-02-08
    • 2023-04-06
    • 1970-01-01
    • 2014-12-19
    • 1970-01-01
    相关资源
    最近更新 更多