Как создать глобальную переменную и изменить в нескольких местах в golang html/template?
Я создаю переменную в 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
вне условия? Может ли кто-нибудь помочь мне с этим?
1 ответ
Короткий ответ: вы не можете.
Согласно философии дизайна, шаблоны не должны содержать сложной логики. В шаблонах вы можете только создавать новые переменные, вы не можете изменять значения существующих переменных шаблона. Когда вы делаете {{$currentUserId := .UserData.UserId}}
внутри {{if}}
блок, который создает новую переменную, которая затеняет внешнюю, и ее область действия распространяется на {{end}}
действие.
Это описано в text/template
пакет, раздел переменных (то же самое относится и к html/template
пакет тоже)
Область действия переменной распространяется на действие "end" структуры управления ("if", "with" или "range"), в которой она объявлена, или до конца шаблона, если такой структуры управления нет. Вызов шаблона не наследует переменные с момента его вызова.
Возможные обходные пути
В вашем случае проще всего зарегистрировать пользовательскую функцию CurrentUserId()
на ваш шаблон, который, если UserData
присутствует, возвращает его идентификатор 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
затем он выполняет шаблон с UserData
имеющий UserId = 99
, Выход:
Current user id: 0
Current user id: 99
Попробуйте это на игровой площадке Go.
Имитация изменяемых переменных
Вы также можете моделировать изменяемые переменные, но также и с зарегистрированными пользовательскими функциями. Вы можете зарегистрировать функцию как SetCurrentUserId()
который изменит значение переменной, предпочтительно в параметрах, которые передаются в выполнение шаблона, так что он остается безопасным для одновременного использования.
Это пример того, как это сделать (он использует map
в качестве данных шаблона и SetCurrentUserId()
устанавливает текущий идентификатор пользователя в качестве значения на этой карте):
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
затем он выполняет шаблон с UserData
имеющий UserId = 99
, Выход:
Before:
Inside: 0
After: 0
Before: 0
Inside: 99
After: 99
Попробуйте это на игровой площадке Go.