Go模板和函数
Go template and function
在我的go代码中,我经常这样使用if
if user && user.Registered { }
go 模板中的等效代码是
{{ if and .User .User.Registered }} {{ end }}
不幸的是,模板中的代码失败了,如果 .User
是 nil
:/
是否可以在 go 模板中实现相同的功能?
模板 and
函数不像 Go &&
运算符那样进行 short circuit 求值。
and
函数的参数在函数被调用之前计算。表达式 .User.Registered
总是被求值,即使 .User
为 nil。
修复方法是使用嵌套 if
:
{{if .User}}{{if .User.Registered}} {{end}}{{end}}
您可以使用模板函数避免嵌套的 if
或 with
:
func isRegistered(u *user) bool {
return u != nil && u.Registered
}
const tmpl = `{{if isRegistered .User}}registered{{else}}not registered{{end}}`
t := template.Must(template.New("").Funcs(template.FuncMap{"isRegistered": isRegistered}).Parse(tmpl))
另一种选择是使用 {{with}}
操作而不是 and
模板函数。
引用自 text/template
的包文档:
{{with pipeline}} T1 {{end}}
If the value of the pipeline is empty, no output is generated;
otherwise, dot is set to the value of the pipeline and T1 is
executed.
使用 {{with}}
通常会产生更简洁、更短的代码,因为在 {{with}}
中,点 .
已经设置为 non-empty "wrapper", .User
在我们的例子中;此外,您不必担心如何以及是否评估 and
模板函数的参数。
您的模板已重写:
{{with .User -}}
{{if .Registered}}REGISTERED{{end}}
{{- end}}
在没有用户和有用户的情况下进行测试:
t := template.Must(template.New("").Parse(tmpl))
fmt.Println("No user:")
if err := t.Execute(os.Stdout, nil); err != nil {
panic(err)
}
u := struct{ Registered bool }{true}
fmt.Printf("User: %+v\n", u)
if err := t.Execute(os.Stdout, map[string]interface{}{"User": u}); err != nil {
panic(err)
}
输出(在 Go Playground 上尝试):
No user:
User: {Registered:true}
REGISTERED
在我的go代码中,我经常这样使用if
if user && user.Registered { }
go 模板中的等效代码是
{{ if and .User .User.Registered }} {{ end }}
不幸的是,模板中的代码失败了,如果 .User
是 nil
:/
是否可以在 go 模板中实现相同的功能?
模板 and
函数不像 Go &&
运算符那样进行 short circuit 求值。
and
函数的参数在函数被调用之前计算。表达式 .User.Registered
总是被求值,即使 .User
为 nil。
修复方法是使用嵌套 if
:
{{if .User}}{{if .User.Registered}} {{end}}{{end}}
您可以使用模板函数避免嵌套的 if
或 with
:
func isRegistered(u *user) bool {
return u != nil && u.Registered
}
const tmpl = `{{if isRegistered .User}}registered{{else}}not registered{{end}}`
t := template.Must(template.New("").Funcs(template.FuncMap{"isRegistered": isRegistered}).Parse(tmpl))
另一种选择是使用 {{with}}
操作而不是 and
模板函数。
引用自 text/template
的包文档:
{{with pipeline}} T1 {{end}} If the value of the pipeline is empty, no output is generated; otherwise, dot is set to the value of the pipeline and T1 is executed.
使用 {{with}}
通常会产生更简洁、更短的代码,因为在 {{with}}
中,点 .
已经设置为 non-empty "wrapper", .User
在我们的例子中;此外,您不必担心如何以及是否评估 and
模板函数的参数。
您的模板已重写:
{{with .User -}}
{{if .Registered}}REGISTERED{{end}}
{{- end}}
在没有用户和有用户的情况下进行测试:
t := template.Must(template.New("").Parse(tmpl))
fmt.Println("No user:")
if err := t.Execute(os.Stdout, nil); err != nil {
panic(err)
}
u := struct{ Registered bool }{true}
fmt.Printf("User: %+v\n", u)
if err := t.Execute(os.Stdout, map[string]interface{}{"User": u}); err != nil {
panic(err)
}
输出(在 Go Playground 上尝试):
No user:
User: {Registered:true}
REGISTERED