2017-02-13 78 views
3

在我去的代码,我经常使用if这样转到模板和功能

if user && user.Registered { } 

在去模板等效代码将

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

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

在go模板中可以实现同样的功能吗?

回答

5

模板and函数不会做short circuit评估像Go &&运算符。

and函数的参数在函数调用之前进行求值。总是评估表达式.User.Registered,即使.User为零。

解决方法是使用嵌套if

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

+0

我想使用嵌套ifs进行转义..因为它会在 – Goranek

+0

之间重复太多的模板代码,即使这并非我真正接受的解决方案。 – Goranek

2

另一种选择是使用:

{{if .User}}{{if .UserRegistered}} {{end}}{{end}} 

您可以通过使用模板函数避免嵌套ifwith{{with}}而不是and模板函数。

text/template包doc引用:

{{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 
+0

不幸的是,这与使用嵌套ifs相同,我试图不使用 – Goranek

+0

@Goranek你没有在你的问题中提到。 – icza

+0

对不起,我认为这是显而易见的,我想实现:( – Goranek