Golang入門.4 -template.ParseFilesを追う-

## はじめに
[Golang入門.3 -html/templateを使う-](https://qiita.com/ryuji0123/items/8d97d21bf06cf6b0cf59)の続きです。

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

## 概念
[document](https://golang.org/pkg/html/template/#ParseFiles)
> ParseFiles creates a new Template and parses the template definitions from the named files. The returned template's name will have the (base) name and (parsed) contents of the first file. There must be at least one file. If an error occurs, parsing stops and the returned *Template is nil.
> When parsing multiple files with the same name in different directories, the last one mentioned will be the one that results. For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template named "foo", while "a/foo" is unavailable.

## コード
　documentによると、`Template`構造体を返しているようです。まず定義を確認します。

```go
// Template is a specialized Template from "text/template" that produces a safe
// HTML document fragment.
type Template struct {
	// Sticky error if escaping fails, or escapeOK if succeeded.
	escapeErr error
	// We could embed the text/template field, but it's safer not to because
	// we need to keep our version of the name space and the underlying
	// template's in sync.
	text *template.Template
	// The underlying template's parse tree, updated to be HTML-safe.
	Tree       *parse.Tree
	*nameSpace // common to all associated templates
}
```

　まず、`text/template`の`Template`構造体を`field`に持っています。また、`HTML`のデータ構造に合わせた処理を行うために必要なものを組み合わせています。構造体についての概要を掴めたので実際に処理を見ていきます。

```go
// ParseFiles creates a new Template and parses the template definitions from
// the named files. The returned template's name will have the (base) name and
// (parsed) contents of the first file. There must be at least one file.
// If an error occurs, parsing stops and the returned *Template is nil.
//
// When parsing multiple files with the same name in different directories,
// the last one mentioned will be the one that results.
// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template
// named "foo", while "a/foo" is unavailable.
func ParseFiles(filenames ...string) (*Template, error) {
	return parseFiles(nil, filenames...)
}
```

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

```go
// parseFiles is the helper for the method and function. If the argument
// template is nil, it is created from the first file.
func parseFiles(t *Template, filenames ...string) (*Template, error) {
	if err := t.checkCanParse(); err != nil {
		return nil, err
	}

	if len(filenames) == 0 {
		// Not really a problem, but be consistent.
		return nil, fmt.Errorf("html/template: no files named in call to ParseFiles")
	}
	for _, filename := range filenames {
		b, err := ioutil.ReadFile(filename)
		if err != nil {
			return nil, err
		}
		s := string(b)
		name := filepath.Base(filename)
		// First template becomes return value if not already defined,
		// and we use that one for subsequent New calls to associate
		// all the templates together. Also, if this file has the same name
		// as t, this file becomes the contents of t, so
		//  t, err := New(name).Funcs(xxx).ParseFiles(name)
		// works. Otherwise we create a new template associated with t.
		var tmpl *Template
		if t == nil {
			t = New(name)
		}
		if name == t.Name() {
			tmpl = t
		} else {
			tmpl = t.New(name)
		}
		_, err = tmpl.Parse(s)
		if err != nil {
			return nil, err
		}
	}
	return t, nil
}
```

　例外処理を行なった後に、与えられたファイル一覧をイテレートしています。各ファイルについて、

1. 中身をbyte形式で取得(b)
2. byteからstringに変換(s)
3. ファイルの名前を取得(name)
4. （最初のファイルについて処理している時のみ）`Template`構造体の生成(t)
5. `Template`構造体の名前空間を構築(t.nameSpace)

した後に生成した`Template`構造体を返しています。
　最後に、途中で登場している`tmpl`について説明します。`tmpl`は現在処理を行なっているファイル情報を格納した`Template`構造体の変数です。

```go
		if name == t.Name() {
			tmpl = t
		} else {
			tmpl = t.New(name)
		}
```

という部分に書いてあるように、一番最初に作った`Template`構造体と同一の`name`を有する場合は`tmpl`と`t`は同一です。しかし、２番目以降のファイルについては`t`を生成せずに`tmpl`のみを生成します。最終的には全てのファイルについての情報を返す必要があります。例えば全てのファイルについての名前空間を`t.nameSpace`に格納する必要があります。そのためには`tmpl.nameSpace`の情報を`t.nameSpace`に共有する必要があります。共有のために必要な処理が`t.New`関数に書いてあると予想し、確認します。

```go
// New allocates a new HTML template associated with the given one
// and with the same delimiters. The association, which is transitive,
// allows one template to invoke another with a {{template}} action.
//
// If a template with the given name already exists, the new HTML template
// will replace it. The existing template will be reset and disassociated with
// t.
func (t *Template) New(name string) *Template {
	t.nameSpace.mu.Lock()
	defer t.nameSpace.mu.Unlock()
	return t.new(name)
}
```

　ここでは`mutex`を用いた制御を`t.new`関数に付与しています。どうやら実際の処理は`t.new`関数に記されているようです。

```go
// new is the implementation of New, without the lock.
func (t *Template) new(name string) *Template {
	tmpl := &Template{
		nil,
		t.text.New(name),
		nil,
		t.nameSpace,
	}
	if existing, ok := tmpl.set[name]; ok {
		emptyTmpl := New(existing.Name())
		*existing = *emptyTmpl
	}
	tmpl.set[name] = tmpl
	return tmpl
}
```

 `tmpl.text`と`tmpl.nameSpace`が`t.New`および`t.nameSpace`として定義されているところがポイントです。これにより`tmpl`の`field`を更新するだけで自然に`t`に必要な情報が追加されます。そして、全てのファイルについて`tmpl`を生成、更新することで`t`に必要な情報が集約されていきます。