Golang模板变量Isset [英] Golang template variable isset

查看:152
本文介绍了Golang模板变量Isset的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个函数来检查是否定义了变量:

  fm ["isset"] = func(a interface {})bool {如果a == nil ||一个==" ||a == 0 {fmt.Println(未设置")返回假}fmt.Println(已设置")返回假}tmpl:= template.Must(template.New(").Funcs(fm).ParseFiles("templates/header.html"))错误:= tmpl.ExecuteTemplate(w,"header",templateData) 

在模板中,我有:

  {{如果isset .Email}}电子邮件已设置{{ 结尾 }} 

如果变量包含在 templateData (这是一个包含映射和字符串的自定义结构)中,则此函数有效,但是如果变量不存在,则会给我一个错误.

错误是:

 在< .Email>处执行标头":无法评估类型为base.customData的字段Email 

在我的情况下,"base.go"是处理程序,"customData"是通过以下类型定义的: type customData struct {..} .

我希望能够重用模板并仅在从处理程序发送了一些变量的情况下显示某些部分.知道如何在模板端实现变量 isset 检查吗?

我还尝试使用: {{if .Email}}做东西{{end}} ,但这也给了我同样的错误.

有什么主意吗?

解决方案

推荐方式

首先,推荐的方法是不依赖于结构字段是否存在.当然,模板中可能有可选部分,但是决定是否渲染零件的条件应取决于所有情况下都存在的字段.

问题,并避免使用地图

如果模板数据的类型是 struct (或指向struct的指针),并且没有给定名称的字段或方法,则模板引擎将为此返回错误./p>

如果要使用地图,则可以轻松摆脱此错误,因为可以使用地图不包含的键以及零值值类型(而不是错误).

为演示,请参见以下示例:

  s:=`{{if .Email}}电子邮件是:{{.Email}} {{else}}电子邮件未设置.{{end}}`t:= template.Must(template.New(").Parse(s))exec:= func(name string,param interface {}){fmt.Printf("\ n%s:\ n",名称)如果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 {电邮字串} {电子邮件:"as@as.com"})exec("Empty struct",struct {} {}) 

输出(在转到游乐场上尝试):

 填写的地图:电子邮件是:as @ as空图:电子邮件未设置.填充结构:电子邮件是:as@as.com空结构:错误:模板::1:5:在< .Email>处执行":无法评估struct {}类型的字段Email 

粘贴到 struct 并提供"isset"

如果必须或要坚持使用 struct ,则可以实现并提供此"isset",我将其称为 avail().

此实现使用反射,并且为了检查其名称给定的字段是否存在(可用),还必须将(包装器)数据传递给它:

  func可用(名称字符串,数据接口{}),bool {v:= reflect.ValueOf(数据)如果v.Kind()== reflect.Ptr {v = v.Elem()}如果v.Kind()!= reflect.Struct {返回假}返回v.FieldByName(name).IsValid()} 

使用它的示例:

  s:=`{{if(可用"Email".)}}}电子邮件是:{{.Email}} {{else}}电子邮件不可用.{{end}}`t:= template.Must(template.New(").Funcs(template.FuncMap {有效":有效,}).解析)exec:= func(name string,param interface {}){fmt.Printf("\ n%s:\ n",名称)如果err:= t.Execute(os.Stdout,param);err!= nil {fmt.Println("Error:",err)}}exec("Filled struct",struct {电邮字串} {电子邮件:"as@as.com"})exec("Empty struct",struct {} {}) 

输出(在转到游乐场上尝试):

 填充的结构:电子邮件是:as@as.com空结构:电子邮件不可用. 

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?

解决方案

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("\n%s:\n  ", 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("\n%s:\n  ", 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.

这篇关于Golang模板变量Isset的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆