dongsaoshuo4326 2017-06-21 11:41
浏览 188
已采纳

Golang模板变量Isset

I have created a function to check if a variable is defined:

fm["isset"] = func(a interface{}) bool {
        if a == nil || a == "" || a == 0 {
            fmt.Println("is not set")
            return false
        }
        fmt.Println("is set")
        return false
    }

tmpl :=  template.Must(template.New("").Funcs(fm).ParseFiles("templates/header.html"))

err := tmpl.ExecuteTemplate(w, "header", templateData)

In the template I have:

{{ if isset .Email }}
    email is set
{{ end }}

This function works if the variable is contained by the templateData (which is a custom struct that contains a map and a string), but it gives me an error if the variable doesn't exist.

The error is:

executing "header" at <.Email>: can't evaluate field Email in type base.customData

In my case "base.go" is the handler and "customData" is defined by: type customData struct{..}.

I want to be able to reuse templates and to display some sections only if some variables are sent from the handler. Any idea how can I implement a variable isset check on the template side?

I also tried using: {{ if .Email}} do stuff {{ end }} but this also gives me the same error.

Any idea?

  • 写回答

2条回答 默认 最新

  • douxin0251 2017-06-21 12:29
    关注

    The recommended way

    First, the recommended way is not to rely on whether a struct field exists. Of course there might be optional parts of the template, but the condition to decide whether to render a part should rely on fields that exist in all cases.

    The issue, and avoiding it using a map

    If the type of the template data is a struct (or a pointer to a struct) and there is no field or method with the given name, the template engine returns an error for that.

    You could easily get rid of this error if you were to use a map, as maps can be indexed with keys they don't contain, and the result of that index expression is the zero value of the value type (and not an error).

    To demonstrate, see this example:

    s := `{{if .Email}}Email is: {{.Email}}{{else}}Email is NOT set.{{end}}`
    
    t := template.Must(template.New("").Parse(s))
    exec := func(name string, param interface{}) {
        fmt.Printf("
    %s:
      ", name)
        if err := t.Execute(os.Stdout, param); err != nil {
            fmt.Println("Error:", err)
        }
    }
    
    exec("Filled map", map[string]interface{}{"Email": "as@as"})
    exec("Empty map", map[string]interface{}{})
    
    exec("Filled struct", struct {
        Email string
    }{Email: "as@as.com"})
    exec("Empty struct", struct{}{})
    

    Output (try it on the Go Playground):

    Filled map:
      Email is: as@as
    Empty map:
      Email is NOT set.
    Filled struct:
      Email is: as@as.com
    Empty struct:
      Error: template: :1:5: executing "" at <.Email>: can't evaluate field Email in type struct {}
    

    Sticking to struct and providing "isset"

    If you must or want to stick to a struct, this "isset" can be implemented and provided, I'll call it avail().

    This implementation uses reflection, and in order to check if the field given by its name exists (is available), the (wrapper) data must also be passed to it:

    func avail(name string, data interface{}) bool {
        v := reflect.ValueOf(data)
        if v.Kind() == reflect.Ptr {
            v = v.Elem()
        }
        if v.Kind() != reflect.Struct {
            return false
        }
        return v.FieldByName(name).IsValid()
    }
    

    Example using it:

    s := `{{if (avail "Email" .)}}Email is: {{.Email}}{{else}}Email is unavailable.{{end}}`
    
    t := template.Must(template.New("").Funcs(template.FuncMap{
        "avail": avail,
    }).Parse(s))
    exec := func(name string, param interface{}) {
        fmt.Printf("
    %s:
      ", name)
        if err := t.Execute(os.Stdout, param); err != nil {
            fmt.Println("Error:", err)
        }
    }
    
    exec("Filled struct", struct {
        Email string
    }{Email: "as@as.com"})
    exec("Empty struct", struct{}{})
    

    Output (try it on the Go Playground):

    Filled struct:
      Email is: as@as.com
    Empty struct:
      Email is unavailable.
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 关于哈夫曼树应用得到一些问题
  • ¥15 使用sql server语句实现下面两个实验(需要代码和运行结果截图)
  • ¥20 用web解决,要给我一个完整的网页,符合上述的要求
  • ¥20 求个sql server代码和结果的图 两道题
  • ¥15 银河麒麟操作系统无法使用U盘
  • ¥100 寻找:光电二极管电路设计服务
  • ¥15 YOLOv5改进后的结构图
  • ¥15 全志v3s怎么设置高速时钟,使用的荔枝派zero开发板,串口2需要921600的波特率
  • ¥15 关于#单片机#的问题:Lora通讯模块hc-14电路图求内部原理图
  • ¥50 esp32 wroom 32e 芯片解锁