doushi3202 2017-03-16 14:04
浏览 48
已采纳

如何将数据添加到Go中用作参数的接口?

I'm just picking up go, so apologies if my terminology isn't precise. My end goal is to add the name of a cachebusted CSS file to the layout template of my Go application. The CSS file built on the fly when the application starts up so can't be hardcoded. In my template file I have this:

//More html here
<link href="{{.CSSFile}}" rel="stylesheet">
//more html here 

I have a Render method on a View type like shown below. It takes data interface{} as an argument and then runs ExecuteTemplate. It is called by every controller in one way or another that sends the data argument and exposes information. I know how to add it as data from the controller that then calls the Render method, but I obviously don't want to add the CSS file in every single controller action, so it makes the most sense to add it in the Render function one time and have it added to the data that gets passed to ExecuteTemplate. My issue is how do I add this information to the data already being passed to Render and then pass that whole of information to ExecuteTemplate. What I have below works for the CSS file, but it obviously doesn't send along the data that was passed to the original Render argument.

type View struct {
    Template *template.Template
    Layout   string
}


func (v *View) Render(w http.ResponseWriter, data interface{}) error {
    d := Data{}
    d.AddCSSFile()
    w.Header().Set("Content-Type", "text/html")
    err := v.Template.ExecuteTemplate(w, v.Layout, d)
    if err != nil {
        log.Println(err)
        fmt.Fprintln(w, "<h1>Something went wrong. Please contact us at support")
    }
    return nil
}

type Data struct {
    Alerts  []Alert
    Yield   interface{}
    CSSFile interface{}
}


func (d *Data) AddCSSFile() {
    ss, _ := filepath.Glob("./assets/site-*.css")
    fp := strings.Join(ss, "")
    _, d.CSSFile = filepath.Split(fp)
}

I've created a gist which, not entirely complete, is a little more fleshed out of what I'm trying to do: https://gist.github.com/codelitt/549a68149add0482c6dc2514a46aa580

  • 写回答

1条回答 默认 最新

  • dongmiao520892 2017-03-16 14:33
    关注

    Not sure I understand exactly what you're asking but if what you want is to combine the data interface{} argument with the d := Data{} value inside Render, then you could do something like this...

    // ...
    
    func (v *View) Render(w http.ResponseWriter, data interface{}) error {
        p := Page{Data:data}
        p.AddCSSFile()
        w.Header().Set("Content-Type", "text/html")
        err := v.Template.ExecuteTemplate(w, v.Layout, p)
        if err != nil {
            log.Println(err)
            fmt.Fprintln(w, "<h1>Something went wrong. Please contact us at support")
        }
        return nil
    }
    
    type Page struct {
        Alerts  []Alert
        Yield   interface{}
        CSSFile interface{}
        Data interface{}
    }
    func (p *Page) AddCSSFile() {
         // ...
    }
    

    Edit: Or you could also just initialize an anonymous struct value and pass it to ExecuteTemplate without having to change you existing Data type.

    // ...
    
    err := v.Template.ExecuteTemplate(w, v.Layout, struct{
        Data
        Args interface{}
    }{Data:d, Args:data})
    
    // ...
    

    Edit2: So if I understand your comment correctly the data interface{} argument passed to the Render method could in some or all instances be or contain a value of a type that matches one of the Data fields' types, in which case you would like to set that value to that field so as to pass it together to the ExecuteTemplate method. At least one solution to that, as you've already found out, is to use type assertion. Below is a slightly modified version of your example from the comment in the context of your original example from the question.

    func (v *View) Render(w http.ResponseWriter, data interface{}) error {
        d := Data{}
        d.AddCSSFile()
        if alerts, ok := data.([]Alert); ok {
            d.Alerts = alerts
        }
    
        w.Header().Set("Content-Type", "text/html")
        err := v.Template.ExecuteTemplate(w, v.Layout, d)
        if err != nil {
            log.Println(err)
            fmt.Fprintln(w, "<h1>Something went wrong. Please contact us at support")
        }
        return nil
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 电力市场出清matlab yalmip kkt 双层优化问题
  • ¥30 ros小车路径规划实现不了,如何解决?(操作系统-ubuntu)
  • ¥20 matlab yalmip kkt 双层优化问题
  • ¥15 如何在3D高斯飞溅的渲染的场景中获得一个可控的旋转物体
  • ¥88 实在没有想法,需要个思路
  • ¥15 MATLAB报错输入参数太多
  • ¥15 python中合并修改日期相同的CSV文件并按照修改日期的名字命名文件
  • ¥15 有赏,i卡绘世画不出
  • ¥15 如何用stata画出文献中常见的安慰剂检验图
  • ¥15 c语言链表结构体数据插入