GoのTemplateのPipelines(パイプライン)を理解しながら、テンプレート内で関数にスライスを引数で渡してみる

Goのテンプレートの中で関数を使い、その関数に引数を渡す

GoでMVCなアプリを書くときに重宝するであろう、templateパッケージ

そのtemplateパッケージを使用してGoでテンプレートを書き、その中で関数を呼び出し、引数に構造体のフィールド上に存在するスライスの要素を渡す

GoのtemplateのPipelinesを理解するのにも役に立つと思うのでメモ

GoのTemplateでスライスを扱うには

Goのtemplateのあらかじめ定義されたグローバル関数であるindexを使用する

indexは

最初の引数を続く引数でインデックスした結果を返します。 例えば"index x 1 2 3"はGoの文法では x[1][2][3]となります。 インデックスされる値はマップ、スライス、配列である必要があります。 (引用元:http://golang-jp.org/pkg/text/template/)

GoのTemplateで関数を扱うには

FuncMapで関数の名前と関数のmapを定義する
詳しくは、後述のコードを参照

GoのPipelines(パイプライン)とは

パイプラインはパイプライン文字'|‘で区切ってコマンドをつなげることによって「連鎖」させることができます。 連鎖されたパイプラインでは、各コマンドの結果は次のコマンドへ最後の引数として渡されます。 パイプラインにおける最後のコマンドの出力がそのパイプラインの値になります。 (引用元: http://golang-jp.org/pkg/text/template/)

例えば、aというコマンドとbというコマンドが存在した場合、

a | b

というコードは、Goでは、aのコマンドの実行結果が、bのコマンドの最後の引数となる

実装してみる

package main

import (
    "html/template"
    "net/http"
    "log"
)
// メイン関数
func main() {
    // ハンドラをバンドル
    http.HandleFunc("/", Handler)

    // リスナー
    if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

// テンプレートを生成
func Handler(w http.ResponseWriter, r *http.Request) {
    // 構造体Programを生成
    p := &Program{Languages:[]string{"Go", "Java", "Python", "JavaScript"},}

    // 関数を名前をつけてtemplateのFuncMapに登録
    funcMap := template.FuncMap{
        "judgeLangType" : JudgeLangType,
    }

    // テンプレート部分
    text := `
  Go : {{ index .Languages 0 | judgeLangType}}
  Java : {{ index .Languages 1 | judgeLangType}}
  Python : {{ index .Languages 2 | judgeLangType}}
  JavaScript : {{ index .Languages 3 | judgeLangType}}
  `

    // テンプレートをパースして、http.ResponseWriterに書き込み
    tmpl := template.Must(template.New("calculator").Funcs(funcMap).Parse(text))
    tmpl.Execute(w, p)
}

// 構造体
type Program struct {
    Languages []string
}

// 言語を引数に受けて、その言語の型を返す
func JudgeLangType(lang string) string{
    switch lang {
    case "Go", "Java":
        return "Static"
    case "Python", "JavaScript":
        return "Dynamic"
    default:
        return "unknown"
    }
}

実行結果

 Go : Static
    Java : Static
    Python : Dynamic
    JavaScript : Dynamic
 

上記のコードのテンプレート部分である以下に注目する

   // テンプレート部分
    text := `
  Go : {{ index .Languages 0 | judgeLangType}}
  Java : {{ index .Languages 1 | judgeLangType}}
  Python : {{ index .Languages 2 | judgeLangType}}
  JavaScript : {{ index .Languages 3 | judgeLangType}}
  `
Go : {{ index .Languages 0 | judgeLangType}}
  • index .Languages 0 で、構造体 Program のフィールド Language のスライスの0番目の要素を表している
  • | で、パイプラインを表している
  • judgeLangType は、template.FuncMap で登録した関数を表している

これは、| の左側の index .Languages 0 の結果(Languagesスライスの0番目の要素)が |の右側の judgeLangType 関数の引数になっている

参考にさせていただいたサイト

http://golang-jp.org/pkg/text/template/#FuncMap https://gohugo.io/templates/go-templates/

※ Qiitaでも同一記事を投稿している qiita.com