Go模板和函数

Go template and function

在我的go代码中,我经常这样使用if

if user && user.Registered { }

go 模板中的等效代码是

{{ if and .User .User.Registered }} {{ end }}

不幸的是,模板中的代码失败了,如果 .Usernil :/

是否可以在 go 模板中实现相同的功能?

模板 and 函数不像 Go && 运算符那样进行 short circuit 求值。

and 函数的参数在函数被调用之前计算。表达式 .User.Registered 总是被求值,即使 .User 为 nil。

修复方法是使用嵌套 if:

 {{if .User}}{{if .User.Registered}}  {{end}}{{end}}

您可以使用模板函数避免嵌套的 ifwith

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))

playground example

另一种选择是使用 {{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