Golang入門. 5 -html/template.Executeを追う-

## はじめに
[Golang入門.4 -template.ParseFilesを追う-](https://qiita.com/ryuji0123/items/be0a0d09fa432dab1462)の続きです。

## 今回のテーマ
　`html/template`の関数`Execute`の実装を追います。

## 概念
[document](https://golang.org/pkg/html/template/#Template.Execute)
<img width="664" alt="スクリーンショット 2020-04-18 16.59.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426293/22c6bca4-717d-82cb-6393-beb9146cf280.png">


## コード
　documentによると、特定のデータを`writer`に出力しているようです。また必要に応じてエラーを返しています。内部処理が重要そうなので、実際に処理を見ていきます。

```html/template/template.go
// Execute applies a parsed template to the specified data object,
// writing the output to wr.
// If an error occurs executing the template or writing its output,
// execution stops, but partial results may already have been written to
// the output writer.
// A template may be executed safely in parallel, although if parallel
// executions share a Writer the output may be interleaved.
func (t *Template) Execute(wr io.Writer, data interface{}) error {
	if err := t.escape(); err != nil {
		return err
	}
	return t.text.Execute(wr, data)
}
```

　別の関数を読んでいるようです。そちらを見てみます。

```text/template/exec.go
// Execute applies a parsed template to the specified data object,
// and writes the output to wr.
// If an error occurs executing the template or writing its output,
// execution stops, but partial results may already have been written to
// the output writer.
// A template may be executed safely in parallel, although if parallel
// executions share a Writer the output may be interleaved.
//
// If data is a reflect.Value, the template applies to the concrete
// value that the reflect.Value holds, as in fmt.Print.
func (t *Template) Execute(wr io.Writer, data interface{}) error {
	return t.execute(wr, data)
}
```

　どうやら`Template`構造体の`execute`関数に`writer`と`data`を渡しているようです。今回は`ServeHTTP`関数で受け取った`http.ResponseWriter`を`writer`として渡しています。また、`data`は独自に定義した`Page`構造体を渡しています。次に`Template.execute`関数を確認します。

```text/template/exec.go
func (t *Template) execute(wr io.Writer, data interface{}) (err error) {
	defer errRecover(&err)
	value, ok := data.(reflect.Value)
	if !ok {
		value = reflect.ValueOf(data)
	}
	state := &state{
		tmpl: t,
		wr:   wr,
		vars: []variable{{"$", value}},
	}
	if t.Tree == nil || t.Root == nil {
		state.errorf("%q is an incomplete or empty template", t.Name())
	}
	state.walk(value, t.Root)
	return
}
```

　`state.walk`関数で実際の処理を行なっているようです。先に`state`構造体を確認します。

```text/template/exec.go
// state represents the state of an execution. It's not part of the
// template so that multiple executions of the same template
// can execute in parallel.
type state struct {
	tmpl  *Template
	wr    io.Writer
	node  parse.Node // current node, for errors
	vars  []variable // push-down stack of variable values.
	depth int        // the height of the stack of executing templates.
}
```

　次に、`state.walk`関数を確認します。

```text/template/exec.go
// Walk functions step through the major pieces of the template structure,
// generating output as they go.
func (s *state) walk(dot reflect.Value, node parse.Node) {
	s.at(node)
	switch node := node.(type) {
	case *parse.ActionNode:
		// Do not pop variables so they persist until next end.
		// Also, if the action declares variables, don't print the result.
		val := s.evalPipeline(dot, node.Pipe)
		if len(node.Pipe.Decl) == 0 {
			s.printValue(node, val)
		}
	case *parse.IfNode:
		s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList)
	case *parse.ListNode:
		for _, node := range node.Nodes {
			s.walk(dot, node)
		}
	case *parse.RangeNode:
		s.walkRange(dot, node)
	case *parse.TemplateNode:
		s.walkTemplate(dot, node)
	case *parse.TextNode:
		if _, err := s.wr.Write(node.Text); err != nil {
			s.writeError(err)
		}
	case *parse.WithNode:
		s.walkIfOrWith(parse.NodeWith, dot, node.Pipe, node.List, node.ElseList)
	default:
		s.errorf("unknown node: %s", node)
	}
}
```
　長く書かれていますが、今回関係あるのは以下の2点です。

1. `s.at(node)`によって`s.node`に`walk`関数の引数として定義した`Template.Root`を代入。
2. `s.node`の`type`に応じて分岐。

　この時注意することが一つあります。それは、`switch`が複数回行われていることです。`s.node`には`text/template/parse.Node`の配列である`Nodes`が格納されています。これらには条件に応じてファイルの中身が分割して格納されています。`switch`においては`Nodes`から順に`text/template/parse.Node`を取り出して実行しています。なお、今回の場合は

- {{}}というテンプレートを用いていない場合(`case *parse.TextNode`)
- テンプレートを用いた場合(`case *parse.ActionNode`)


でその後の動作が変わります。前者の場合は`s.wr.Write`である`http.ResponseWriter`の`Write`関数で中身を出力します。
　一方後者の場合は、`s.evalPipeline`によって`eval`を実行してテンプレートにかかれてある処理を実行した後のファイルの中身を取得します。その後、`s.printValue`関数で出力を行なっています。最後に`s.printValue`関数を確認します。

```text/template/exec.go
// printValue writes the textual representation of the value to the output of
// the template.
func (s *state) printValue(n parse.Node, v reflect.Value) {
	s.at(n)
	iface, ok := printableValue(v)
	if !ok {
		s.errorf("can't print %s of type %s", n, v.Type())
	}
	_, err := fmt.Fprint(s.wr, iface)
	if err != nil {
		s.writeError(err)
	}
}
```

　`fmt.Fprintf`関数に`s.wr (http.ResponseWriter)`を渡しています。[以前](https://qiita.com/ryuji0123/items/17bde94e206a89f79d77#%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E8%A7%A3%E8%AA%AC)確認したように、`fmt.Fprintf`関数では最終的に引数の`http.Response.Write`関数を呼び出しています。

## 終わりに
　以前からテンプレートによるhtmlファイルの生成がどのような仕組みで実行されているのか気になっていました。今回、`eval`関数と組み合わせることで実現していることがわかりました。また、`html/template`においても出力には`http.ResponseWriter.Write`関数によって出力していることがわかりました。