在Go的HTML模板中进行字段检测

huangapple go评论68阅读模式
英文:

Field detection in Go HTML template

问题

在Go的HTML模板中,是否可以检查结构体字段是否存在?

例如,给定以下模板:

{{if .FieldA}}
    <a>{{.FieldA}}</a>
{{end}}

和以下结构体定义:

type MyStruct struct{  
    FieldA string
    FieldB string
}

// 在这个结构体中,FieldA 不存在
type MyStruct2 struct{  
    FieldB string
}

MyStruct 传递给模板是可以正常工作的。然而,将 MyStruct2 传递给模板会导致错误。虽然 if 语句可以检查 nil 值,但当它遇到当前结构体中不存在的字段时,它会抛出错误(终止模板执行器)。

有时,特定字段只会在某些结构体中可用,所以有没有办法在尝试访问字段之前检查它是否存在?

我在官方文档中没有找到解决方案,因此得出结论可能没有优雅的解决方法。

英文:

Is it possible to check if a struct field exists from within a Go HTML template?

For example, given the following template:

{{if .FieldA}}
    &lt;a&gt;{{.FieldA}}&lt;/a&gt;
{{end}

and structs defined as:

type MyStruct struct{  
    var FieldA string
    var FieldB string
}
// In this struct FieldA is unavailable
type MyStruct2 struct{  
    var FieldB string
}

Passing MyStruct into the template will work fine. However, passing MyStruct2 into the template will result in error. While the if statement can check for nil values, it throws an error (killing the template executor) when it encounters a field which doesn't exist in the current struct.

Sometimes a particular field is only going to be available in certain structs, so is there a way to check if the field exists prior to attempting to access it?

I've had no luck with the official documentation and have come to the conclusion that perhaps there is no elegant solution.

答案1

得分: 17

这是一个检查字段是否存在的模板函数的示例代码:

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

在模板中使用该函数的方式如下:

{{if hasField . "FieldA"}}<a>{{.FieldA}}</a>{{end}}

在函数映射中添加hasField函数来创建模板:

t := template.New("").Funcs(template.FuncMap{"hasField": hasField}).Parse(d)

你可以在这个playground示例中查看完整的代码。

英文:

There's not a built-in way to check for the presence of a field, but it is possible to write a template function to do the check:

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

Use the function in a template like this:

{{if hasField . &quot;FieldA&quot;}}&lt;a&gt;{{.FieldA}}&lt;/a&gt;{{end}}

Create the template with hasField in the func map:

 t := template.New(&quot;&quot;).Funcs(template.FuncMap{&quot;hasField&quot;: hasField}).Parse(d)

<kbd>playground example</kbd>

huangapple
  • 本文由 发表于 2016年1月10日 15:29:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/34703133.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定