template.FuncMapとFuncs()を用いることで、
templateに対して関数を登録する事ができます。
階層が次のようになっているとします。
main.go
templates
blabla.gohtml
tpl1.gohtml
tpl2.gohtml
main.goの内容です。
var tpl *template.Template
var fm = template.FuncMap{
"uc": strings.ToUpper, // upper caseにする標準メソッド
"ft": firstThree, // オリジナル関数
}
func init() {
tpl = template.Must(template.New("").Funcs(fm).ParseGlob("templates/*")) // Funcs()について後述
}
func firstThree(s string) string { // 引数にとる文字列のうち、冒頭3文字のみを返す関数
s = strings.TrimSpace(s) // スペースを消す標準メソッド
s = s[:3]
return s
}
type team struct {
Name string
League string
}
type player struct {
Name string
Team string
}
func main() {
nf, err := os.Create("index.html")
if err != nil {
log.Fatal(err)
}
ronaldo := &player{
Name: "Ronaldo",
Team: "Juventus",
}
messi := &player{
Name: "Messi",
Team: "Barcelona",
}
players := []*player{ronaldo, messi}
err = tpl.ExecuteTemplate(nf, "tpl1.gohtml", players)
if err != nil {
log.Fatal(err)
}
}
関数を登録するFuncs()はTemplateのポインタレシーバーのため、
Templateのポインタを返すメソッドが事前に必要です。
この条件に適合するNew()を、引数なしで使用しています。
特にその機能を用いるわけではないので、引数は必要ありません。
tplもTemplateのポインタ型であるから、
後でtpl.Funcs()とすれば良いのでは?と思われるかもしれませんが、
Funcs()はParsingの前に実行する必要があるため、それはできません。
tpl1.gohtmlの内容は次の通りとします。
登録したFuncMapのフィールド名を、出力するフィールド名の隣に書きます。
複数の関数を適用する場合は、パイプラインを使用して後方に記述します。
<h1>tpl2</h1>
{{range .}}
<li>{{uc .Name}} : {{.Team | ft | uc}}</li> // 関数を適用。パイプラインを使用して複数指定することも可能
{{end}}
</ol>
index.htmlは次のようになります。
<h1>tpl2</h1>
<li>RONALDO : JUV</li> // playerはucのみ、teamはucとftが適用される
<li>MESSI : BAR</li>
</ol>
templateはMVCモデルで言う所のViewsにあたります。
ViewsがControllersのような役割を担うことに反対する意見もあるかと思います。
しかしtemplateにてdataを取得する際に加工できることは、
少なからずメリットがあることですので、覚えておくに越したことはないかと思います。
今回の例でお見せしたような、文字をupper castするようなもの、
スライスの中から適宜欲しいものだけを抽出するようなものなど、一定の利用用途はあるはずです。
その場合の分だけgoファイルにてdataを用意すると、膨大・複雑化することも考えられます。
このような、templateに関数を登録した方がスッキリとする場合もあるでしょう。