Quel est l'espace de noms des variables à l'intérieur de html/text
modèles? Je pensais qu'une variable $x
peut changer la valeur à l'intérieur d'un modèle, mais cet exemple me montre que je ne peux pas.
J'ai échoué lorsque j'ai essayé de regrouper les tournois en fonction de l'année - quelque chose comme ça ( http://play.golang.org/p/EX1Aut_ULD ):
package main
import (
"fmt"
"os"
"text/template"
"time"
)
func main() {
tournaments := []struct {
Place string
Date time.Time
}{
// for clarity - date is sorted, we don't need sort it again
{"Town1", time.Date(2015, time.November, 10, 23, 0, 0, 0, time.Local)},
{"Town2", time.Date(2015, time.October, 10, 23, 0, 0, 0, time.Local)},
{"Town3", time.Date(2014, time.November, 10, 23, 0, 0, 0, time.Local)},
}
t, err := template.New("").Parse(`
{{$prev_year:=0}}
{{range .}}
{{with .Date}}
{{$year:=.Year}}
{{if ne $year $prev_year}}
Actions in year {{$year}}:
{{$prev_year:=$year}}
{{end}}
{{end}}
{{.Place}}, {{.Date}}
{{end}}
`)
if err != nil {
panic(err)
}
err = t.Execute(os.Stdout, tournaments)
if err != nil {
fmt.Println("executing template:", err)
}
}
Modifier: voir https://stackoverflow.com/a/52925780/1685538 pour une réponse plus à jour.
Réponse originale:
https://golang.org/pkg/text/template/#hdr-Variables :
La portée d'une variable s'étend à l'action "fin" de la structure de contrôle ("si", "avec" ou "plage") dans laquelle elle est déclarée, ou à la fin du modèle s'il n'y a pas une telle structure de contrôle.
Alors le $prev_year
vous définissez avec {{$prev_year:=$year}}
ne vit que jusqu'à .. la ligne suivante ({{end}}
).
Il semble qu'il n'y ait aucun moyen de contourner cela.
La "bonne" façon de procéder consiste à retirer cette logique de votre modèle et à effectuer le regroupement dans votre code Go.
Voici un exemple de travail: https://play.golang.org/p/DZoSXo9WQR
package main
import (
"fmt"
"os"
"text/template"
"time"
)
type Tournament struct {
Place string
Date time.Time
}
type TournamentGroup struct {
Year int
Tournaments []Tournament
}
func groupTournamentsByYear(tournaments []Tournament) []TournamentGroup {
if len(tournaments) == 0 {
return nil
}
result := []TournamentGroup{
{
Year: tournaments[0].Date.Year(),
Tournaments: make([]Tournament, 0, 1),
},
}
i := 0
for _, tournament := range tournaments {
year := tournament.Date.Year()
if result[i].Year == year {
// Add to existing group
result[i].Tournaments = append(result[i].Tournaments, tournament)
} else {
// New group
result = append(result, TournamentGroup{
Year: year,
Tournaments: []Tournament{
tournament,
},
})
i++
}
}
return result
}
func main() {
tournaments := []Tournament{
// for clarity - date is sorted, we don't need sort it again
{"Town1", time.Date(2015, time.November, 10, 23, 0, 0, 0, time.Local)},
{"Town2", time.Date(2015, time.October, 10, 23, 0, 0, 0, time.Local)},
{"Town3", time.Date(2014, time.November, 10, 23, 0, 0, 0, time.Local)},
}
t, err := template.New("").Parse(`
{{$prev_year:=0}}
{{range .}}
Actions in year {{.Year}}:
{{range .Tournaments}}
{{.Place}}, {{.Date}}
{{end}}
{{end}}
`)
if err != nil {
panic(err)
}
err = t.Execute(os.Stdout, groupTournamentsByYear(tournaments))
if err != nil {
fmt.Println("executing template:", err)
}
}
Dans go1.11 text/template et donc html/template est devenu capable de définir la valeur des variables existantes , ce qui signifie que le code original peut être fait fonctionner avec une très petite modification.
Changement
{{$prev_year:=$year}}
À
{{$prev_year = $year}}
Comme mentionné par la réponse this , la portée de cette variable "réassignation" se termine par {{end}}
bloquer. Par conséquent, en utilisant uniquement des variables standard il n'y a aucun moyen de contourner le problème et il doit être résolu dans le programme Go exécutant le modèle.
Dans certains cadres, cependant, ce n'est pas si simple (par exemple, protocol-gen-gotemplate).
La bibliothèque Sprig ajoute des fonctionnalités supplémentaires au langage de modèle standard. L'un d'eux sont des cartes mutables qui peuvent être utilisées de la manière suivante:
// init the dictionary (you can init it without initial key/values as well)
{{$myVar := dict "key" "value"}}
// getting the "key" from the dictionary (returns array) and then fetching the first element from that array
{{pluck "key" $myVar | first}}
// conditional update block
{{if eq "some" "some"}}
// the $_ seems necessary because Go template functions need to return something
{{$_ := set $myVar "key" "newValue"}}
{{end}}
// print out the updated value
{{pluck "key" $myVar | first}}
Ce petit exemple imprime:
value
newValue
Une approche pragmatique consisterait à utiliser un dictionnaire unique pour toutes les variables mutables et à les stocker sous leur nom de variable correspondant comme clé.
Référence: