template.FuncMap【Go】
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に関数を登録した方がスッキリとする場合もあるでしょう。