技術向上

プログラミングの学び、気になるテクノロジーやビジネストレンドを発信

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