gpt4 book ai didi

html - 如何在golang html/template中创建一个全局变量并在多个地方进行更改?

转载 作者:IT王子 更新时间:2023-10-29 02:22:24 28 4
gpt4 key购买 nike

我正在 html/template 中创建一个变量,并根据条件更改值。但是值的范围只停留在 if 条件内:

{{if .UserData}}
{{$currentUserId := .UserData.UserId}}
[<a href="#ask_question">Inside {{$currentUserId}}</a>]
{{else}}
{{$currentUserId := 0}}
{{end}}
[<a href="#ask_question">outside {{$currentUserId}}</a>]

在 if 条件内我得到正确的值但在它之外是 0。如何在条件之外使用 $currentUserId?有人可以帮我解决这个问题吗?

最佳答案

Go 1.11 添加了对 changing values of template variables 的支持.要定义变量,请使用 :=:

{{$currentUserId := 0}}

要改变它的值,使用赋值=:

{{$currentUserId = .UserData.UserId}}

如果变量在 {{if}} block 之外创建但在其中更改,则更改将在 {{if}} block 之后可见。

{{$currentUserId := 0 -}}
Before: {{$currentUserId}}
{{if .UserData -}}
{{$currentUserId = .UserData.UserId}}
[<a href="#ask_question">Inside {{$currentUserId}}</a>]
{{else}}
{{$currentUserId = 0}}
{{end}}
[<a href="#ask_question">outside {{$currentUserId}}</a>]

像这样测试:

m := map[string]interface{}{}
t := template.Must(template.New("").Parse(src))

m["UserData"] = UserData{99}
if err := t.Execute(os.Stdout, m); err != nil {
panic(err)

输出是(在 Go Playground 上尝试):

Before: 0

[<a href="#ask_question">Inside 99</a>]

[<a href="#ask_question">outside 99</a>]

原始答案如下。


简短的回答是:你不能。

根据设计理念,模板不应包含复杂的逻辑。在模板中,您只能创建新变量,不能更改现有模板变量的值。当您在 {{if}} block 中执行 {{$currentUserId := .UserData.UserId}} 时,会创建一个新变量来遮蔽外部变量,并且它的范围扩展到 {{end}} 操作。

这在 text/template 中有描述包,Variables section (这同样适用于 html/template 包):

A variable's scope extends to the "end" action of the control structure ("if", "with", or "range") in which it is declared, or to the end of the template if there is no such control structure. A template invocation does not inherit variables from the point of its invocation.

可能的解决方法

在您的情况下,最简单的方法是将自定义函数 CurrentUserId() 注册到您的模板,如果存在 UserData,则返回其 ID UserData.UserId (),如果它不存在,则返回 0,就像您的情况一样。

这是一个如何完成的例子:

type UserData struct {
UserId int
}

func main() {
m := map[string]interface{}{}
t := template.Must(template.New("").Funcs(template.FuncMap{
"CurrentUserId": func() int {
if u, ok := m["UserData"]; ok {
return u.(UserData).UserId
}
return 0
},
}).Parse(src))

if err := t.Execute(os.Stdout, m); err != nil {
panic(err)
}
m["UserData"] = UserData{99}
if err := t.Execute(os.Stdout, m); err != nil {
panic(err)
}
}

const src = `Current user id: {{CurrentUserId}}
`

它首先执行不带 UserData 的模板,然后执行带 UserDataUserId = 99 的模板。输出是:

Current user id: 0
Current user id: 99

Go Playground 上试试.

模拟可变变量

您还可以模拟可变变量,但也可以使用已注册的自定义函数。您可以注册一个像 SetCurrentUserId() 这样的函数,它会更改变量的值,最好是在传递给模板执行的参数中,这样它在并发使用时仍然是安全的。

这是一个如何操作的示例(它使用 map 作为模板数据,并且 SetCurrentUserId() 将当前用户 ID 设置为该映射中的值) :

func main() {
m := map[string]interface{}{}
t := template.Must(template.New("").Funcs(template.FuncMap{
"SetCurrentUserId": func(id int) string {
m["CurrentUserId"] = id
return ""
},
}).Parse(src))

if err := t.Execute(os.Stdout, m); err != nil {
panic(err)
}
m["UserData"] = UserData{99}
if err := t.Execute(os.Stdout, m); err != nil {
panic(err)
}
}

const src = `Before: {{.CurrentUserId}}
{{if .UserData}}
{{SetCurrentUserId .UserData.UserId}}Inside: {{.CurrentUserId}}
{{else}}
{{SetCurrentUserId 0}}Inside: {{.CurrentUserId}}
{{end}}
After: {{.CurrentUserId}}
`

这再次首先执行不带 UserData 的模板,然后执行带 UserDataUserId = 99 的模板。输出是:

Before: 
Inside: 0
After: 0
Before: 0
Inside: 99
After: 99

Go Playground 上试试.

关于html - 如何在golang html/template中创建一个全局变量并在多个地方进行更改?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41962055/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com