去模板和功能

时间:2017-02-13 16:05:57

标签: go go-templates

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

if user && user.Registered { }

go模板中的等效代码将是

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

如果.Usernil:/

,则模板中的代码会失败

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

2 个答案:

答案 0 :(得分:11)

模板and功能不像Go &&运算符那样进行short circuit评估。

在调用函数之前,会计算and函数的参数。即使.User.Registered为零,也始终评估表达式.User

修复方法是使用嵌套的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

答案 1 :(得分:3)

另一种选择是使用{{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}}内部的点.已经设置为非空"包装"在我们的案例中.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